Graphing queue get/put rates

I want to graph the production and consumption rates of messages on a queue. What is the best way to do this?

There are two main ways of doing this, with MQGem Software tools, and these two methods have various pros and cons, which I would like to show and discuss in the post.

Graph Reset QStats

Here is a screen shot of a graph of the enqueue and dequeue values from a Reset QStats command. Instructions on how to create this graph will be given at the end of the blog post.

MO71 Graph produced from a monitor using the RESET QSTATS command

Graph Queue Statistics

Here is a screen shot of a graph of the total of successful puts and total of successful gets from Queue Statistics. Instructions on how to create this graph will be given at the end of the blog post.

MO71 Graph produced from MQEV Queue Statistics data

Which should I use?

There are different characteristics of these two ways of graphing what is in essence the same data. Let’s look at them side by side.

Reset QStats Queue Statistics
Polls the Command Server. Care should be taken if you are monitoring large numbers of queues at high frequencies using this method because of the incurred load on the queue manager. However, for single queue high frequency graphs, this may be more suitable as you would you not likely want to set Accounting and Statistics intervals to really short timeframes, such as a minute or less. Information is pushed by the Queue Manager as Accounting and Statistics messages, at configured intervals, and it therefore incurs less load on the queue manager.
Can only be graphed by one user as RESET QSTATS is destructive Can be graphed by any number of users
Using RESET QSTATS will interfere with the collection of Performance Events Using Queue Statistics does not interfere with any other data collection
Available on z/OS (turn on performance events to use it) and Distributed platforms Only available on Distributed platforms, not on z/OS
Configuration is very simple to monitor a small number of queues, but becomes unwieldly to monitor many/all queues Configuration requires a small amount of initial set up, but once set up, monitoring the entire queue manager is no more effort than monitoring a single queue
MO71 does not harden this data, so the data must processed/graphed immediately MQEV will keep the accounting data for as long as you tell it to – 3 months by default. At any time you can request to see historical data for any of your queues.
Can be done using only MO71 Requires MQEV

In summary, MO71 is an administration tool, that provides a few simple monitoring capabilities, but it is not a full blown monitoring tool. If you just want to see what happens to a few objects for a short period of time, say whilst diagnosing a specific problem, then it is a suitable solution. However, if you have more wide-spread, or longer-term monitoring requirements, particularly if there is a requirement to harden the data, then MQEV is the more appropriate choice, with MO71 providing the graphing interface on top of that data.

Creating Graph Using Reset QStats

In order to create a graph of integer values obtained by sending commands to the command server, you must first create a “monitor”. This is what sends the commands and collects the responses so that you have data to graph. Begin at the Monitor menu and choose Monitor List… From this dialog you can make a New… monitor from the right-click context menu and fill in the details of the command and attributes you wish to monitor. Here’s my monitor definition.

MO71 “monitor” definition

Once you have created it, start the monitor and it will begin to send command messages to the command server in order to collect the data.

Now you can graph the data which the monitor has collected. Begin at the Monitor menu and choose Graph… This will display the graphing canvas which is currently blank. Right click on the graphing canvas to set up your graph.

Any running “monitors” you have will be shown on the Monitors tab. Open up the twisty for your queue manager to see the sets of data you have available to graph. In my case I have chosen to collect data on two attributes from the Reset QStats command, so I see that I have a set of data for each attribute.

To add each set of data to the graph, click on the empty square to the left, to tick the line. At the same time you can also choose graph type, colour, thickness and so on. With graphs such as these, where both lines are quite similar, you may find it useful to invert the Msgs Out, which is what the graph illustrated did.

Having created your graph with appropriate sets of data and the colours you want, remember that there are other options on the “Graph” tab of this dialog. For example, you can give the graph an appropriate title, which will then be reflected in the graph window title.

Creating Graph Using Queue Statistics

To collect Queue Statistics for a single queue, you can enable it on that queue alone.

ALTER QLOCAL(WORK.Q1) STATQ(ON)

Alternatively, you can enable Queue Statistics for many/all queues by enabling it on the queue manager.

ALTER QMGR STATQ(ON)

Either way, the interval (in seconds) upon which statistics data will be pushed out by the queue manager is configured on the queue manager object.

ALTER QMGR STATINT(900)

MQEV will collect the statistics data for you. Ensure that MQEV is running and reading from the appropriate SYSTEM queue.

=mqev
RESUME EVQ(SYSTEM.ADMIN.STATISTICS.QUEUE)

Once you have MQEV collecting MQ Statistics data, you can graph the data that it has collection. Begin at the Monitor menu and choose Graph… This will display the graphing canvas which is currently blank. Right click on the graphing canvas to set up your graph.

For Queue Statistics data you should switch to the StatQ tab. Before you open up the twisty to see the data, configure the time period you wish to graph and the summation interval to be used. I have my interval set to 15 minutes to match the collection interval. My time period was chosen to make the graph look pretty! You should do this first because these settings are used by MO71 when it sends commands to MQEV to get the data to graph.

Now open up the twisty for your queue manager to see the sets of data you have available to graph. You will see all the integer values available from Queue Statistics records (this screenshot is truncated for reasons for brevity).

To add each set of data to the graph, click on the empty square to the left, to tick the line. At the same time you can also choose graph type, colour, thickness and so on. With graphs such as these, where both lines are quite similar, you may find it useful to invert the gets, which is what the graph illustrated did.

Having created your graph with appropriate sets of data and the colours you want, remember that there are other options on the “Graph” tab of this dialog. For example, you can give the graph an appropriate title, which will then be reflected in the graph window title.


If you don’t have a licence and would like to try out MO71 and MQEV then send an email to support@mqgem.com and a 1-month trial licence will be sent to you.

Latest MQEV and MQSCX released on z/OS

Our recently released versions of MQEV V9.2.2 and MQSCX V9.2.1 are now also available on z/OS.

Read more about these versions here:-


The new versions can be downloaded from the MQEV Download Page and the MQSCX Download Page. Any current licensed users of these products can run the new version on their existing licence. If you don’t have a licence and would like to try out MQEV or MQSCX then send an email to support@mqgem.com and a 1-month trial licence will be sent to you.

Post Event Data to HTTP Service

In an earlier blog post we looked at how MQEV emitters can write out your IBM MQ Event, Accounting and Statistics data, to files or queues for post-processing. One of the examples of the types of post-processing you might use this for was to upload JSON format data to an HTTP centralised service such as Elastic. This post is going to look at that in more detail.

As a user of MQ, you will understand the benefits of decoupling applications by using a queue. The example of posting event data to an HTTP service is a good example of a case where this decoupling is very useful. Rather than have MQEV do the HTTP post as part of consuming the event message, it instead writes the JSON data to a queue. This means that the mainline processing of event messages is not impacted if the HTTP post cannot be completed right at this moment. Then we have another application which reads the messages from that queue and posts them to the HTTP service.

This application can be triggered so that it starts up when it needs to. If the data is from event messages, these arrive on a non-deterministic pattern. If it’s Statistics data, the data arrives every 30 minutes, say. Accounting data is a combination of the two, the data will arrive at set intervals, but also when the application disconnects. In all cases, there is likely to be a lot of waiting around, so triggering is perfect.

MQGem supplies a GetPost Python application that reads from the queue, checks that the data is valid JSON, and then posts the data to the specified URL. This application meets the needs for this particular MQEV use case, but might be useful for other scenarios too. We offer it as a free application to anyone who can find a use for it.

We chose Python for this application because we needed a language that had MQ libraries, HTTP libraries and JSON libraries. Python met the requirements, and allows a single application to be written that can run on many of the main business platforms[1].

The GetPost application currently provides two ways to post the data to a URL.

  1. General Purpose POST of JSON data
    MQEV emits data in JSON. This data can be posted exactly as it appears in the message data, but does require the use of the MQEV emitter attribute GROUPING(SINGLE). This is a basic form of Get->Post and will be suitable for a number of HTTP services. It works with Elastic too.
  2. Elastic Bulk Data POST
    This mode is specifically for use with Elastic and utilises the Elastic Bulk API which can POST multiple items with a single HTTP POST. This is especially useful when you have emitters using GROUPING(ORIGINAL) on Accounting and Statistics data such that there are multiple items in a single emitted message. This provides an efficiency not available with the general purpose method which has to post each message as a separate HTTP POST.

    This mode also takes the unique identifier from the MQEV message data and uses that as the unique Elastic _id allowing the detection of duplicate POSTS. This is very useful since, of course, an HTTP POST is not able to be transactional. It is therefore preferential to use this mode even when no grouping is in use.

Once the data is input into Elastic, you can graph it and display in many different ways. However, likely as not, if you are interested in Elastic, you know more about this than we do!

Graph of Queue Statistics showing the maxdepth attribute for each queue over a number of intervals


The new version of MQEV can be downloaded from the MQEV Download Page, and the User Manual for MQEV also describes the GetPost application. The GetPost application can be downloaded from the GetPost Webpage. Any current licensed users of MQEV can run the new version on their existing licence. If you don’t have a licence and would like to try out MQEV then send an email to support@mqgem.com and a 1-month trial licence will be sent to you.


Footnotes:

  1. Only today, I discovered that Python is also available on z/OS when I read Top 8 Reasons for using Python instead of REXX for z/OS, so I will have to look into that too. And more recently still, we now have PyMQI libraries for z/OS thanks to Colin Paice.

MQEV Emitters

A new feature added to MQEV V9.2.2 is emitters. This feature allows you to configure MQEV to emit the data it has gathered about events, accounting and statistics, to files or queues in a chosen format, JSON, CSV or MQSC. This can make it easy to ingest this data into downstream processes.

You might want to do this because:-

  • You have a centralised system for capturing such data, such as Elastic or Splunk.
  • You want to post-process and graph numeric data such as Accounting and Statistics.
  • You wish to maintain a long term archive of event data.
  • You can also use it to debug your queue manager event settings and MQEV config to easily see the events being captured and processed as they come in, for example by directing the incoming events to a queue in MQSC format, and having an application sitting in a get wait on that queue.

This post is going to describe how to set them up.

EV Streams

The first thing to look at is EV Streams. This is the control point to break out the different types of data you are collecting. By default, MQEV gives you one for each type of data as shown in the table below, but you can create more detailed breakdowns than that, as described in an earlier post Retaining Events with MQEV. In our diagram we have a stream called CFGEV where we have stored all the configuration events.

Type of data Default EV Stream Name Grouping
Events $EVENTS Always single
Accounting MQI $ACCTMQI Always single
Accounting Queue $ACCTQ Arrays possible
Statistics MQI $STATMQI Always single
Statistics Queue $STATQ Arrays possible
Statistics Channel $STATCHL Arrays possible

EV Streams are also the control point where you configure EV Emitters. You’ll want a particular type of data to be emitted in a particular way, or not at all.

EV Emitters

An EV Emitter is a new configuration object in MQEV that details the file or queue you want data to be emitted to, the format (JSON, CSV, or MQSC) and various other controls on that data.Here’s an example command to create an emitter to a queue.

DEFINE EVEMIT(JSON.TO.Q) QUEUE(EVENTS.JSON.EMIT) +
       DESCR('Emit Event data in JSON to a queue') +
       FORMAT(JSON) +
       READER(PROGRAM) +
       GROUPING(SINGLE) +
       MSGPERS(YES) +
       ONERROR(SUSPEND)

Let’s look in more detail at this configuration.

  • We’ve given it a name that explains it’s purpose, it’s to be used to emit JSON format data to a queue.
  • This emitter will write the data as messages to a queue, and we’ve named the queue here to describe the contents.
  • The emitter knows to write JSON messages because of the FORMAT attribute.
  • The READER attribute will change the style the output is written in. Either quite compressed, with very few new lines, and thus hard for a human to read, or spaced out, indented, plenty of newlines, to make it easy for a human to read. The content is the same for either READER(PROGRAM) or READER(HUMAN), it’s just the whitespace that changes, and thus can make the message a bit bigger.
  • For some types of data (as shown in the table above), arrays of records are possible, and can be a more efficient way to work with the data. If you want to force each record to be an individual emitted message, you can use GROUPING(SINGLE). For the types where the data is always single anyway, this attribute has no effect.
  • Emitted messages can take their persistence from the original event message that was created by the queue manager – MSGPERS(ASMSG) – or alternatively you can set it explicitly as this example shows.
  • Finally, you need to decide what behaviour you want in case of an error, say your emitter queue fills up. You can choose to suspend reading from the event queue while you sort out the issue, or you can choose to discard the emitted message and continue processing from the event queue.

Having created your emitter definition, you then associate it with the stream as follows:-

ALTER EVSTREAM(CFGEV) EVEMIT(JSON.TO.Q)

Emitting to files

In addition to what we have seen about emitters, there is a little more to say when emitting data to a file. When emitting to a queue, each item is written as a message to the queue. When emitting to a file, you probably want multiple items to end up in the same file. For example, you might want a CSV file containing all the Queue Statistics Data for one day, giving you several rows in the one file, and making it easy to graph that data.

One of the things that dictates the way the file is used is the name of the file, more specifically the inserts in the file name.

Our above example of capturing a days worth of data in a single file, could be done as follows using the %C insert which is for the current date:-

DEFINE EVEMIT(CSV.TO.FL) FILE('C:\MQGem\StatQ%C.csv') +
       DESCR('Emit StatQ data in CSV to a file') +
       FORMAT(CSV) +
       READER(PROGRAM)

It is possible to force each item to create a new file, by using the %i insert, which is just an index on the file name.

There are a wide selection of inserts which you can see full details about in the MQEV User Manual.

Downstream processing

Having got MQEV to write data to a file, you can then process it using tools that understand the particular file type, for example a spreadsheet to use a CSV file.

Having got MQEV to write data to a queue, you need to have something processing that queue. If your data is in JSON format and you need to upload it to a central service that listens on an HTTP listener, you may find the GetPost application useful. Read more about this application here.

Summary

So we have expanded a little on the detail of how to configure an MQEV Emitter. Our flow picture has expanded to show more of the steps.


The new version can be downloaded from the MQEV Download Page. Any current licensed users of MQEV can run the new version on their existing licence. If you don’t have a licence and would like to try out MQEV then send an email to support@mqgem.com and a 1-month trial licence will be sent to you.

MQEV version 9.2.2 is released

MQGem Software is pleased to announce that a new version of MQEV, our Event Processing tool for IBM MQ, is now available.

The main features of the release are as follows:-

Addition of Emitters

You can use MQEV to emit events, accounting and statistics data, ready to push to a centralised store such as Elastic. Alternatively, you can have all your data written out as files ready to import into a spreadsheet. Both of these cases, and others you may have, are catered for by MQEV emitters. These can be configured in MQEV to write out data from events, accounting or statistics, to queues or files, in JSON, CSV or MQSC format.

You can choose any subset of your events, by first setting up your data to different streams, MQEV’s control point for your data. Then the set of data that goes to one stream, is emitted based on the configuration associated with that stream.

Read more about MQEV Emitters in this blog post.

Improvements for large sets of data

Commands to interrogate MQEV already have limits on them so that if you simply type in DISPLAY EVENTS(*) you don’t end up with an unwieldy number of results. By default results are limited to only return 100 results (equivalent of typing MAXRESP(100)) and also to only return those results from the past day (equivalent of typing FROM(-24h)). However, if you have millions of records captured in a day, more likely for Accounting and Statistics than Events, and you request a totalled answer, by using a command something like the following, then that might be a very large set of data that needed to be processed and totalled to give you your answer as a single response.

DISPLAY ACCTMQI(*) SUM(TOTAL)

To protect against inadvertent processing of large sets of data, MQEV now has a second limiting concept for DISPLAY commands, called MaxRecords (MAXRECS), which controls the number of records that will be processed in a DISPLAY command. If there were more records than that, the command would warn you that the record set had been limited, and you could consider whether you really wanted to total up more than a million records, and, if so, raise the limit, or alternatively, filter the records used so that the set of records was less than a million, perhaps by only looking at the last 8 hours, instead of the last 24 hours, for example.

For many users, the need to increase MAXRECS from it’s default of 1 million will be unnecessary, but for those users with these large sets of data, they can increase the default used for MAXRECS in the ALTER EV command, using the DEFMAXRECS attribute.

Support for hex types in MQEV WHERE clause

A number of fields in events, accounting and statistics records are hexadecimal, such as ConnectionIds, or Channel error codes. It is now possible to filter on these types in the MQEV WHERE clause.

DISPLAY ACCTMQI(*) SUM(NONE) ALL
        WHERE(CONNID EQ 0x'414D51434D514732202020202020202010CAE36001CCCD23')

See build date when running MQEV in background

When you run MQEV in the foreground, the first thing it does is report the build date.

MQEV Version:9.2.2 (64 Bit) Build Date:Dec 10 2021

However, when running it in the background, or as a service, you can’t just look in that foreground window. It is written in the log file, but that’s not your normal way of interacting with MQEV. So now you can discover this using the DISPLAY EV command.

NAME(MQEV)          DESCR(MQGem Software IBM MQ Event Processor)
STARTTI(2021-12-10 22:16:50 (Local))  BUILD(Dec 10 2021)
CMDLEVEL(922)

Command Level support up to 924

MQEV now supports queue managers up to the most recently released command level of 924.


The new version can be downloaded from the MQEV Download Page. Any current licensed users of MQEV can run the new version on their existing licence. If you don’t have a licence and would like to try out MQEV then send an email to support@mqgem.com and a 1-month trial licence will be sent to you.

Are you using any back-level clients?

We have a list of questions that MQEV can help you to answer. One of them is:-

  • What version of MQ client are connecting to my Queue Manager? Are any of them old and in need of an update?

In this post I want to show you how to answer that question.

You may be aware that the version of the MQ client is something that is flowed across to the server. Originally it was just used to write out in trace for IBM Service; then it was added as output on DISPLAY CHSTATUS; and then in MQ V8.0.0.3 it was given to channel exits, and then in MQ V9.1.0, it was added to MQI accounting records.

Capturing this data using accounting records is an excellent way to do it because you don’t have to worry about missing connections from applications that are so short lived that you can’t catch them with a DISPLAY CHSTATUS command. An MQI accounting record is written for each application at disconnect time (explicit MQDISC or implicit), but also periodically every ACCTINT if the connection duration is long enough and the application is doing any MQI work.

To do this, you turn on MQI Accounting records, using the following MQSC command.

ALTER QMGR ACCTMQI(ON)

Then tell MQEV to monitor the accounting queue with the following MQEV command.

RESUME EVQ(SYSTEM.ADMIN.ACCOUNTING.QUEUE)

Then you will get data for each application that connects to your queue manager. At the start of each record of this type will be various identifying fields about the application. For example the application name, the channel name it connected across (assuming it is a client), and the connection name it came from. In addition you will see the remote product and remote version of the client.

MO71 display Accounting MQI records for clients with different Remote Versions

If you don’t have any reason to collect MQI accounting, apart from answering this question, you could simply raise an Alert when you see a client older than a certain level, and then discard the rest of the data. Here’s how you would do that in the mqev.mqx script.

*********************************************************************
* Function for processing an Accounting MQI message                 *
*********************************************************************
func MQEVAcctMQI()
  if (data.CHANNEL)
    if (data.RVERSION < "09020000")
      @AlertStr  = "Application: " + data.ACCTMQI + -
                 " from CONNAME: " + data.CONNAME + -
                 " has a back-level client version: " + data.RVERSION
      @AlertObj  = data.CHANNEL
      @AlertQMgr = data.EVQMGR
      ADD EVALERT TEXT('<@AlertStr>') CATEGORY(CLIENTVER) +
          EVOBJNAME('<@AlertObj>') EVOBJTYPE(CHANNEL)     +
          SEVERITY(WARN) EVQMGR('<@AlertQMgr>') REPLACE
    endif
  endif
  *******************************************************************
  * Discard the MQI data - I have got all I needed from it          *
  *******************************************************************
  _stream = "$null"
endfunc

MQEV alerts can be displayed using a GUI such as MO71 or a command line tool such as MQSCX. When using MO71, if the alert list dialog is open, it will be automatically refreshed every time a new alert is added since MO71 subscribes to a topic that gets a publication with every new alert. The use of REPLACE in the above script means that only one alert will be written for each unique client. So if the same client application connects 100s of times, there will still only be one alert. Once the administrator believes the back-level client has been upgraded, the alert can be deleted from MQEV, and should it appear again, you know the problem is not yet fixed.

MO71 list of MQEV Alerts showing some back-level clients

You can read more about MQEV Alerts in this blog post.


Read more about MQEV, and download a copy, from the MQEV Web Page. If you don’t have a licence and would like to try out MQEV before deciding whether to buy then send an email to support@mqgem.com and a 1-month trial licence will be sent to you.

Running MQEV as an MQ SERVICE

If you have IBM MQ Event Switches enabled, whenever your queue manager is running, you should have a program consuming the event messages that are generated. If you don’t, your event queues will fill up, and newer event messages will be silently discarded by the queue manager.

One way to ensure that there is always a program running, and consuming these messages, while the queue manager is running, is to define that program as an MQ SERVICE object, and let the queue manager start it up. You can do this with any program, and MQEV is no exception.

In MQEV V9.2.0, we added an additional flag, -k, that tells MQEV it is being run in this mode which changes the way it behaves a little:-

  • It will run in background mode (just as if you had specified -b)
  • It will not retry connection failures, but instead just end. It will be running as a locally bound connection, and so these failures will be as a result of the queue manager ending (normally or abnormally). When the queue manager next starts up, so will MQEV. It was possible to mimic this prior to MQEV V9.2.0 by using -r none, but that had the effect of suppressing retry of all failures. -k only suppresses connection failure retry.

So to run MQEV as an MQ service, you need a definition like this on your queue manager (along with the two queues that MQEV uses).

DEFINE SERVICE(MQGEM.MQEV) +
       DESCR('MQGem Software Event Monitor') +
       CONTROL(QMGR) SERVTYPE(SERVER) +
       STARTCMD('mqev') STARTARG('-m +QMNAME+ -k') +
     [ STOPCMD('mqscx') STOPARG('-m +QMNAME+ -f -C "=mqev;STOP EV"') ]

To explain the various parameters:-

  • CONTROL(QMGR) ensures the program is started when the queue manager starts up.
  • SERVTYPE(SERVER) says that there is only one instance of this SERVICE running at any one time, and allows you to use the DISPLAY SVSTATUS command to check whether it is running.

    MO71 showing a list of Service Status containing MQEV

  • The STARTCMD names the program, which in my case is in the path, and STARTARG provides the parameters. The use of +QMNAME+ is a short-hand on SERVICE objects for the name of the owning queue manager. This means you don’t have to change the definition to copy it to other queue managers.
  • The STOPCMD is optional, because MQEV will end when it detects the queue manager is quiescing, or gets any other connection failure.
    • It might be useful to code the STOPCMD and STOPARG if you are developing your event scripts, for easy stop and restart of MQEV using the STOP SERVICE and START SERVICE MQSC commands. However, you can just as easily issue the STOP EV command via MQSCX or MO71 interactively.
    • The STOPARG are parameters to the MQSCX program, and tell it to run the initial command (-C) of =mqev followed by STOP EV.

Read more about MQEV, and download a copy, from the MQEV Web Page. If you don’t have a licence and would like to try out MQEV before deciding whether to buy then send an email to support@mqgem.com and a 1-month trial licence will be sent to you.

MQEV on z/OS

The recent release of MQEV V9.2 included the provision of MQEV to run natively on the z/OS platform.

When collecting event messages from your IBM MQ Queue Manager, it is most appropriate to run the event collecting application local to the queue manager. To this end, getting MQEV running natively on z/OS was important to us.

Started Task

You can run MQEV in a number of environments on z/OS, but we imagine running it as a started task will be the most prevalent. Here’s an example started task procedure that you might copy to your procedure library and name something like MQG1MQEV to go along with your queue manager MQG1’s tasks MQG1MSTR and MQG1CHIN. The IBM-supplied procedure library is called SYS1.PROCLIB, but your installation might use its own naming convention.

//*********************************************************************
//* Run MQEV program                                 
//*********************************************************************
//         PROC QMGR=MQG1
//PROCSTEP EXEC PGM=MQEV,
//         PARM=('-m &QMGR')
//*
//STEPLIB  DD DSN=GEMUSER.USER.LOAD,DISP=SHR                         
//         DD DSN=IBM.MQ.SCSQAUTH,DISP=SHR                           
//         DD DSN=IBM.MQ.SCSQANLE,DISP=SHR                           
//SYSPRINT DD SYSOUT=*  
//SYSOUT   DD SYSOUT=*      
//MQGEML   DD DSN=GEMUSER.MQGEM.LIC,DISP=SHR
//MQEVMQX  DD DSN=MQGEM.MQEV.SCRIPTS(MQEV),DISP=SHR
//MQEVLOG  DD DSN=MQGEM.MQEV.LOGS.&QMGR,DISP=SHR
//

There are a number of DD names coded in the above JCL which make setting up your MQEV configuration easier, and keep the JCL PARM string short.

DD name MQGEML

The MQEV program must be able to find your MQGem Software licence file in order to be able to run. This is a licence file specific for MQEV on z/OS. A distributed platform licence will not enable MQEV on z/OS to run. The MQGEML DD name points to that file, which can be an MVS file or an HFS file. All MQGem licences can be concatenated into one file, so it is appropriate to put them all in a central location and have all MQGem Software programs look to the same place.

DD name MQEVMQX

The MQEV program must be able to find the MQEV script. This can be located using the -f program parameter, however in JCL it is neater to use this DD name to locate it instead. The script file can be an MVS file or an HFS file.

DD name MQEVLOG

The MQEV program needs to know where to write out its log files. This can be located using the -L program parameter, however in JCL it is neater to use this DD name to locate the MVS library or HFS directory instead. Note in this example how the library name contains the queue manager name which is very good practice when setting up the logging for MQEV.

Starting and Stopping MQEV

If MQEV is defined as a procedure you can start it using the MVS start command, thus:

COMMAND INPUT ===> /START MQG1MQEV

MQEV can be stopped by sending the STOP EV command to it’s command server (i.e. via the MQGEM.MQEV.COMMAND.QUEUE) using MQSCX or MO71. MQEV on z/OS has an additional stop mechanism as it is coded to listen for the MVS stop command. So you can choose to stop it using the MVS stop command, thus:

COMMAND INPUT ===> /STOP MQG1MQEV

Interactive

When developing MQEV scripts to act upon different events being noticed, you may find it useful to run MQEV interactively. This allows you to debug your scripts by stepping through them line by line, or to set breakpoints to stop on specific situations.

MQEV on z/OS can run interactively in z/OS UNIX, in OMVS or in TSO.

For example, here’s MQEV being run in debugging mode in TSO, inspecting some event variables when the MQEVEvent() function is called.

 FNC:    1 > func MQEVEvent()
 DBG>
print event.summary
 Command - Change Qmgr - Qmgr:MQG1
 DBG>
print event.evobjname
 MQG1
 DBG>

MQEV running on z/OS can process event messages and operate on them just in the same was as MQEV running on a distributed platform and connecting to your z/OS queue manager over a client. Running MQEV on z/OS gives you the benefit of avoiding the cost of the client connection and keeping all your event data processing on the z/OS machine.

Tools to interrogate MQEV to discover the details of event messages can either run on z/OS (for example MQSCX for z/OS) or can attach as clients (for example MO71). In this latter case, answers to questions about event messages are delivered over client connections, but in this case only the data the user is interested in need be sent over the client connection, rather than every single event message.


You can download MQEV for z/OS from the MQEV Download Page. If you’d like to try out MQEV on z/OS, please email support@mqgem.com and a 1-month trial licence will be sent to you.

MQEV version 9.2.0 is released

MQGem Software is pleased to announce that a new version of MQEV, our Event Processing tool for IBM MQ, is now available.

The main features of the release are as follows:-

Run MQEV as a Queue Manager SERVICE object

There is now a -k parameter to indicate MQEV is running as an IBM MQ service. This mode of execution essentially says that MQEV should start and end in line with the Queue Manager itself. So, when the Queue Manager ends MQEV will not attempt any retries. Here’s an example of how you might define your MQEV SERVICE object.

DEFINE SERVICE(MQGEM.MQEV) +
       DESCR('MQGem Software Event Monitor') +
       CONTROL(QMGR) SERVTYPE(SERVER) +
       STARTCMD('mqev') STARTARG('-m +QMNAME+ -k')

Read more about this is Running MQEV as an MQ SERVICE.

MQEV now has a STOP EV command

An administrator can end MQEV at any time by issuing the STOP EV command. This can be issued from MQSCX or through MO71.

New and changed expression functions

MQEV uses the MQSCX control language in its scripting, and there are some new and changed expression functions in this new release (and also in the new MQSCX release – see that post for examples).

  • New: valueof()
    String function to parse files in the format FIELD(VALUE)
  • New: power(x,y)
    Mathematical function returning the value of xy
  • Changed: system()
    The system() function now has an option second parameter to determine whether to run the invoked command synchronously or asynchronously

z/OS Support

MQEV is now available to run locally on the z/OS platform. To enable this you require a z/OS specific licence. A distributed platform MQEV licence will not enable MQEV on z/OS to run. For more on this read this blog post: MQEV on z/OS

Command Level support up to 920

MQEV now supports queue managers up to the most recently released command level of 920.


The new version can be downloaded from the MQEV Download Page. Any current licensed users of MQEV can run the new version on their existing licence. If you don’t have a licence and would like to try out MQEV then send an email to support@mqgem.com and a 1-month trial licence will be sent to you.

Using ALERTS with MQEV

AlertOur event, accounting and statistics monitoring program, MQEV has a feature to raise alerts. They were initially designed to allow you to notify an MQ administrator of something untoward that has been discovered through an event message or with accounting and statistics data, but they actually serve a number of other purposes. This blog post is going to look at the various different ways you can make use of MQEV alerts.

  • Notification to the MQ Administrator
    This is the first, and perhaps most obvious use of alerts in MQEV. For example, upon receiving a Queue Full event, you might raise an alert to notify the MQ administrator of the problem. This could be accompanied by sending an email or text message, for example. In addition, MQEV publishes an MQ message when an alert is raised so that other programs can subscribe to them for speedy notification.

    ****************************************************************
    * Function for processing an event
    ****************************************************************
    func MQEVEvent()
      @objname = event.evobjname
      @objtype = event.evobjtype
      if (event.evreason = PERQDPFULL)
        ************************************************************
        * Alert the MQ Administrator
        ************************************************************
        ADD EVALERT TEXT('Queue High') CATEGORY(VIP) +
            EVOBJNAME('<@objname>') EVOBJTYPE(<@objtype>) +
            SEVERITY(SEVERE) REPLACE
      endif
    endfunc
  • Driving a script after some time passes
    This example is something that is also shown in the MQEV manual. In this case you have noticed a situation that, if it remains for too long, is a problem. However, if it clears up quickly, there is no need to trouble the MQ Administrator. The example uses the receipt of a Queue High event. It raises an informational alert with a short expiry time, and if the Queue High status is still present, and has not been cleared with a subsequent Queue Low event, the expiration of the alert will drive code to notify the MQ administrator of the problem.

    ****************************************************************
    * Function for processing an event
    ****************************************************************
    func MQEVEvent()
      @objname = event.evobjname
      @objtype = event.evobjtype
      if (event.evreason = PERQDPHI)
        ************************************************************
        * Add a temporary alert that will expire in 60 seconds
        ************************************************************
        ADD EVALERT TEXT('Queue High') CATEGORY(QHIGHTEMP) +
            EVOBJNAME('<@objname>') EVOBJTYPE(<@objtype>) +
            SEVERITY(INFO) RETINTVL(60) REPLACE
      endif
      if (event.evreason = PERQDPLO)
        ************************************************************
        * Remove both alert types, temp & final, wildcarded CATEGORY
        ************************************************************
        REMOVE EVALERT TEXT('Queue High') CATEGORY(QHIGH*) +
               EVOBJNAME('<@objname>') EVOBJTYPE(<@objtype>)
      endif
    endfunc
    ****************************************************************
    * Function called when an alert expires
    ****************************************************************
    func MQEVAlertExpire()
      if (alert.category = 'QHIGHTEMP')
        @objname = alert.evobjname
        @objtype = alert.evobjtype
        ADD EVALERT TEXT('Queue High') CATEGORY(QHIGH) +
            EVOBJNAME('<@objname>') EVOBJTYPE(<@objtype>) +
            SEVERITY(WARN) REPLACE
      endif
    endfunc
  • Drive Code repeatedly
    An extension of the above idea, is to use expiring alerts to drive code on a regular basis to check on something, perhaps a behaviour in MQ that isn’t able to be monitored by event messages. After checking the attribute, a new expiring alert, based on the one that just expired, is created, and round it goes again. The MonitorSomething() function might also create alerts of the first type.

    ****************************************************************
    * Function: addEVAlert
    ****************************************************************
    func addEVAlert(Text, Category, RetIntvl)
      =mqev
      ADD EVALERT TEXT('<@Text>') CATEGORY('<@Category>') +
          RETINTVL(<@RetIntvl>) EVQMGR(<_qmgr>) +
          SEVERITY(INFO) REPLACE
      =mqsc
    endfunc
    ****************************************************************
    * Function called when we connect
    ****************************************************************
    func MQEVConnected()
      **************************************************************
      * Initialise the expiring alerts that drive the monitoring fns
      **************************************************************
      addEVAlert("Delay: 2 Hours",   "DELAY.2HRS",  2 * 60 * 60)
    endfunc
    ****************************************************************
    * Function called when we an alert expires
    ****************************************************************
    func MQEVAlertExpire()
      if (alert.CATEGORY = 'DELAY.2HRS')
        MonitorSomething(...)
        * Now remake the same alert *
        addEVAlert(alert.TEXT, alert.CATEGORY, alert.RETINTVL)
      endif
    endfunc
  • Drive some code in an ad hoc manner
    Again, in an extension to the above model, you could have code to run that is driven by an expiring alert, and could be driven in an ad hoc manner by an administrative command creating an alert with a very short expiry.

    ****************************************************************
    * Function called when we an alert expires
    ****************************************************************
    func MQEVAlertExpire()
      if (alert.CATEGORY = 'DRIVE.NOW')
        CheckSomething(...)
      endif
    endfunc

    This code could be driven by an MQ administrator using the following command:

    ADD EVALERT TEXT('Drive code') CATEGORY(DRIVE.NOW) +
        RETINTVL(1) SEVERITY(INFO) REPLACE
  • State Variable
    When monitoring for situations using event messages or even issuing direct MQ commands, you can raise an alert for an MQ Administrator to take notice of what has been discovered. If the same situation is seen again, and the MQ Administrator has not yet noticed the previous alert, you may decide that you don’t need to contact him again. The existence of the alert in the system marks that he has already been notified. Once the MQ Administrator deals with the alert, he can delete it. The lack of an alert in the system would then mean that the script would notify him again if the situation subsequently arose.

    ****************************************************************
    * Function: AlertUser 
    * Purpose: This function will alert the user in whichever way is
    *          needed, for example, raise an alert, or send an email
    ****************************************************************
    func AlertUser(objname, objtype, category, alert_text)
      =mqev
      DIS EVALERT CATEGORY('<@category>') +
          EVOBJTYPE(<@objtype>) EVOBJNAME('<@objname>') +
          EVQMGR(<_qmgr>)
      if (_matches = 0)
        ************************************************************
        * Send email to notify MQ Administrator 
        ************************************************************
        system('email.bat "' + @alert_text + '"')
      else
        @id = EVALERT
        REMOVE EVALERT(<@id>)
      endif
      **************************************************************
      * Always add a new replacing alert so that the date, and any
      * new text in the alert, is updated
      **************************************************************
      ADD EVALERT TEXT('<@alert_text>') CATEGORY('<@category>') +
          EVOBJTYPE(<@objtype>) EVOBJNAME('<@objname>') +
          EVQMGR(<_qmgr>)
      =mqsc
    endfunc

As you can see, MQEV and its alerts are very flexible. Alerts can notify an MQ Administrator of an event within your MQ estate, and in addition can be used to control when those alerts might be raised.


Read more about MQEV, and download a copy, from the MQEV Web Page. If you don’t have a licence and would like to try out MQEV before deciding whether to buy then send an email to support@mqgem.com and a 1-month trial licence will be sent to you.