02
Sat, Nov
2 New Articles

Job Logging from RPG IV--The Easy Way!

RPG
Typography
  • Smaller Small Medium Big Bigger
  • Default Helvetica Segoe Georgia Times

We all know my fondness for subprocedures, but one thing I like even better is prototyping useful APIs and C runtime functions for use by RPG IV programmers.

How many times while in your RPG program have you wanted to record a piece of information to the job log? You basically had two choices: Call a CL program to post the data or call the QMHSNDPM API and set up and pass all those cryptic parameters. Consequently, many RPG developers will go into debug on a program simply to view the contents of a variable or two. Wouldn't it be great to be able to write the contents of virtually any field to the job log, easily, from within RPG IV?

This article illustrates a rather uncommon (and apparently unknown) API that I've been using for years and have incorporated into the RPG xTools. The API is Qp0zLprintf (Print Formatted Job Log Data). Its purpose is to write a message in the job log. Qp0zLprintf is different from calling the message API or a CL program because it writes the text directly to the job log without the clutter of other methods. In fact, if you press F1 on the job log entry, no message ID is written. It does this by sending an impromptu message to the job log.

There are only three rules for calling Qp0zLprintf.

  • The name Qp0zLprintf is case-sensitive and, yes, there is a zero in the middle of the name.
  • You may insert substitution variables at runtime to build the job log entry dynamically.
  • In order for the entry to be written to the job log, you must terminate the text with a "linefeed" character. As I've mentioned in other articles on CGI programming, a linefeed character in RPG IV is represented by X'25', and, no, Qp0zLprintf has nothing to do with CGI programming.

The API is really provided for non-RPG IV programmers who want to log information where iSeries and AS/400 users can find it. But it does make things a bit easier for RPG IV programmers as well. For example, the following writes the text string 'Hello OS/400' out to the job log from within RPG IV, using the Qp0zLprintf API:

     C                   Callp     Qp0zLprintf('Hello OS/400')

You could use job log messages of this type to verify that milestones in the code were being performed in the correct sequence (or even at all). But what if you want to insert some varying data, such as a customer name or number, into a part of a static message? For example, suppose you want the customer number and name to be recorded to the job log, like this:

CustNo: 3470 The Big Software Company

You can use Qp0zLprintf to build this message dynamically at runtime by coding the following:

C                   callp     Qp0zLprintf('CustNo: %s %s': 
C                                %char(CustNo):%Trimr(CustName))

Note the %s values in the message text. These are substitution variable placeholders. These placeholders are part of the Qp0zLprintf API and are based on the C language's age-old printf function. Effectively, it means that each subsequent parameter (following the first parameter's text literal) is automatically inserted into the first parameter in order. So the first %s value is replaced with the content of Qp0zLprintf's second parameter, the second %s is replaced with the content of the third parameter, and so on.

The %s value means the API is expecting a "string"--or more accurately, a C language-style null-terminated string for the associated parameter. There are other substitution symbols for numeric and single characters, but I find that just using %s is easier and more practical in RPG IV. Besides, with the %CHAR() built-in function, converting numeric to character is more than easy to do.

So in our example, the CUSTNO field is converted from numeric to character using the %CHAR built-in function, and then it's inserted into the location of the first %s substitution symbol in your message text. The content of the CUSTNAME field is inserted in place of the second %s substitution symbol. Note that I remove trailing blanks from CUSTNAME just for good measure.

Writing to the Job Log

Of course, the example would not actually send anything to the job log because it was not terminated with a linefeed character. To make this work, you need to change the example to the following:

C                   callp     Qp0zLprintf('CustNo: %s %s' + X'25' : 
C                                %char(CustNo):%Trimr(CustName))

Note the addition of the X'25' character after the original message text. This causes the API to write the message to the job log. With the X'25', the data will just sit out there until either the X'25' is sent or the total length of all the text sent via Qp0zLprintf reaches 512 characters. At that point, the X'25' is forced.

Qp0zLprintf Prototype

Let's look at a prototype, as it appears in the IBM manuals, for the Qp0zLprintf API:

int Qp0zLprintf(char *format-string, ...);

The API has a parameter named format-string, which is straightforward; it is a C language null-terminated string. But the second parameter is not so straightforward; it is an ellipse (...). An ellipse in C means that the parameter may be repeated as necessary. RPG IV does not have an equivalent of this capability, so we have to make due with what can be simulated in RPG IV.

Qp0zLprintf Parameters

The first parameter, as I mentioned, is a C null-terminated string. Passing a parameter of this data type is extremely easy in RPG IV. We simply specify the OPTIONS(*STRING) keyword on the prototype parameter, and the compiler does the conversion from character to null-terminated for us. So the first parameter would be defined as follows:

D  szOutputStg                    *   Value OPTIONS(*STRING)

This is very similar to coding something like the following:

D  szOutputStg                  32A   Const

The difference is, since the API expects a null-terminated string, you would have to call the procedure as follows to make it work:

C                   Callp     Qp0zLprintf('Hello OS/400'+X'00')

Effectively, what you're doing is adding X'00' to the end of the text. This is not pretty. So instead, you code the parameter so that the compiler automatically converts your input value into a null-terminated string and then passes that temporary value to the API. The "length" of a null-terminated string is determined by the location of the X'00' in the string. There is no predefined length for null-terminated strings, but they are limited to a length of 64K minus 1. Using these variables is vaguely similar to using VARYING fields in RPG IV.

The next requirement is to define the second through Nth parameters. It's up to you to decide how many of these parameters you would like to permit. Since you don't have to assign a name to parameter, you can define the parameter once and then copy the line of code as many times as you want.

As I mentioned, the API allows you to insert character, numeric, or strings as substitution parameters. If you convert everything to strings, you only need one type of parameter, one that is similar to the first parameter itself, as follows:

D                                 *   Value OPTIONS(*STRING:*NOPASS)

In this parameter, the OPTIONS(*STRING) keyword is used, but it also includes a second value, *NOPASS. This means the parameter is optional. This is the key to prototyping an API that has a variable number of parameters via the ellipse; you specify OPTIONS(*NOPASS) in addition to everything else you specify.

So the prototype for Qp0zLprintf ends up looking like this:

D Qp0zLprintf     PR            10I 0 ExtProc('Qp0zLprintf')
D  szOutputStg                    *   Value OPTIONS(*STRING)
D                                 *   Value OPTIONS(*STRING:*NOPASS)

Of course, just one substitution variable isn't all that compelling. You want more. So how do you specify more than one substitution parameter? By simply copying the second parameter over and over again until you have enough to handle as many substitution values as you believe you'll need. Remember, these parameters are optional, so when you call the API, you only specify the ones you need. Here's an example of the Qp0zLprintf prototype with 10 substitution variable parameters:

D Qp0zLprintf     PR            10I 0 ExtProc('Qp0zLprintf')
D  szOutputStg                    *   Value OPTIONS(*STRING)
D                                 *   Value OPTIONS(*STRING:*NOPASS)
D                                 *   Value OPTIONS(*STRING:*NOPASS)
D                                 *   Value OPTIONS(*STRING:*NOPASS)
D                                 *   Value OPTIONS(*STRING:*NOPASS)
D                                 *   Value OPTIONS(*STRING:*NOPASS)
D                                 *   Value OPTIONS(*STRING:*NOPASS)
D                                 *   Value OPTIONS(*STRING:*NOPASS)
D                                 *   Value OPTIONS(*STRING:*NOPASS)
D                                 *   Value OPTIONS(*STRING:*NOPASS)
D                                 *   Value OPTIONS(*STRING:*NOPASS)

Now, when you call Qp0zLprintf, you can specify one parameter or more than one parameter. If you specify one parameter, you imply that you're not doing any substitutions; if you specify more than one parameter, you imply that you are doing substitutions.

Now, you can call Qp0zLprintf as follows:

C                   callp     Qp0zLprintf('CustNo: %s %s' + X'25' : 
C                                %char(CustNo):%Trimr(CustName))

And sitting out in the job log will be something similar to the following:

CustNo: 3470 The Big Software Company

Qp0zLprintf is great for logging important debug information to the job log, but if performance is an issue, Qp0zLprintf is not a great choice because the overhead is a bit more than you might expect. I recommend using Qp0zLprintf only to log things you need to know of during debug mode. Or you could create a "switch" in your code that you can turn on externally. Then, if that switch is on, call the Qp0zLprintf; otherwise, bypass it.

Finally, if you're a fan of TRACE, there is an equivalent API to write out to the user trace area. That API is Qp0zUprintf. The only difference is the "U" in the name instead of the "L." The prototype for Qp0zUprintf is as follows:

D Qp0zUprintf     PR            10I 0 ExtProc('Qp0zUprintf')
D  szOutputStg                    *   Value OPTIONS(*STRING)
D                                 *   Value OPTIONS(*STRING:*NOPASS)
D                                 *   Value OPTIONS(*STRING:*NOPASS)
D                                 *   Value OPTIONS(*STRING:*NOPASS)
D                                 *   Value OPTIONS(*STRING:*NOPASS)
D                                 *   Value OPTIONS(*STRING:*NOPASS)
D                                 *   Value OPTIONS(*STRING:*NOPASS)
D                                 *   Value OPTIONS(*STRING:*NOPASS)
D                                 *   Value OPTIONS(*STRING:*NOPASS)
D                                 *   Value OPTIONS(*STRING:*NOPASS)
D                                 *   Value OPTIONS(*STRING:*NOPASS)

To view the data in the user trace space, use the DSPUSRTRC CL command.

Bob Cozzi is a programmer/consultant, writer/author, and software developer. His popular RPG xTools add-on subprocedure library for RPG IV is fast becoming a standard with RPG developers. His book The Modern RPG Language has been the most widely used RPG programming book for more than a decade. He, along with others, speaks at and produces the highly popular RPG World conference for RPG programmers.

BOB COZZI

Bob Cozzi is a programmer/consultant, writer/author, and software developer. His popular RPG xTools add-on subprocedure library for RPG IV is fast becoming a standard with RPG developers. His book The Modern RPG Language has been the most widely used RPG programming book for more than a decade. He, along with others, speaks at and produces the highly popular RPG World conference for RPG programmers.


MC Press books written by Robert Cozzi available now on the MC Press Bookstore.

RPG TnT RPG TnT
Get this jam-packed resource of quick, easy-to-implement RPG tips!
List Price $65.00

Now On Sale

The Modern RPG IV Language The Modern RPG IV Language
Cozzi on everything RPG! What more could you want?
List Price $99.95

Now On Sale

BLOG COMMENTS POWERED BY DISQUS

LATEST COMMENTS

Support MC Press Online

$

Book Reviews

Resource Center

  • SB Profound WC 5536 Have you been wondering about Node.js? Our free Node.js Webinar Series takes you from total beginner to creating a fully-functional IBM i Node.js business application. You can find Part 1 here. In Part 2 of our free Node.js Webinar Series, Brian May teaches you the different tooling options available for writing code, debugging, and using Git for version control. Brian will briefly discuss the different tools available, and demonstrate his preferred setup for Node development on IBM i or any platform. Attend this webinar to learn:

  • SB Profound WP 5539More than ever, there is a demand for IT to deliver innovation. Your IBM i has been an essential part of your business operations for years. However, your organization may struggle to maintain the current system and implement new projects. The thousands of customers we've worked with and surveyed state that expectations regarding the digital footprint and vision of the company are not aligned with the current IT environment.

  • SB HelpSystems ROBOT Generic IBM announced the E1080 servers using the latest Power10 processor in September 2021. The most powerful processor from IBM to date, Power10 is designed to handle the demands of doing business in today’s high-tech atmosphere, including running cloud applications, supporting big data, and managing AI workloads. But what does Power10 mean for your data center? In this recorded webinar, IBMers Dan Sundt and Dylan Boday join IBM Power Champion Tom Huntington for a discussion on why Power10 technology is the right strategic investment if you run IBM i, AIX, or Linux. In this action-packed hour, Tom will share trends from the IBM i and AIX user communities while Dan and Dylan dive into the tech specs for key hardware, including:

  • Magic MarkTRY the one package that solves all your document design and printing challenges on all your platforms. Produce bar code labels, electronic forms, ad hoc reports, and RFID tags – without programming! MarkMagic is the only document design and print solution that combines report writing, WYSIWYG label and forms design, and conditional printing in one integrated product. Make sure your data survives when catastrophe hits. Request your trial now!  Request Now.

  • SB HelpSystems ROBOT GenericForms of ransomware has been around for over 30 years, and with more and more organizations suffering attacks each year, it continues to endure. What has made ransomware such a durable threat and what is the best way to combat it? In order to prevent ransomware, organizations must first understand how it works.

  • SB HelpSystems ROBOT GenericIT security is a top priority for businesses around the world, but most IBM i pros don’t know where to begin—and most cybersecurity experts don’t know IBM i. In this session, Robin Tatam explores the business impact of lax IBM i security, the top vulnerabilities putting IBM i at risk, and the steps you can take to protect your organization. If you’re looking to avoid unexpected downtime or corrupted data, you don’t want to miss this session.

  • SB HelpSystems ROBOT GenericCan you trust all of your users all of the time? A typical end user receives 16 malicious emails each month, but only 17 percent of these phishing campaigns are reported to IT. Once an attack is underway, most organizations won’t discover the breach until six months later. A staggering amount of damage can occur in that time. Despite these risks, 93 percent of organizations are leaving their IBM i systems vulnerable to cybercrime. In this on-demand webinar, IBM i security experts Robin Tatam and Sandi Moore will reveal:

  • FORTRA Disaster protection is vital to every business. Yet, it often consists of patched together procedures that are prone to error. From automatic backups to data encryption to media management, Robot automates the routine (yet often complex) tasks of iSeries backup and recovery, saving you time and money and making the process safer and more reliable. Automate your backups with the Robot Backup and Recovery Solution. Key features include:

  • FORTRAManaging messages on your IBM i can be more than a full-time job if you have to do it manually. Messages need a response and resources must be monitored—often over multiple systems and across platforms. How can you be sure you won’t miss important system events? Automate your message center with the Robot Message Management Solution. Key features include:

  • FORTRAThe thought of printing, distributing, and storing iSeries reports manually may reduce you to tears. Paper and labor costs associated with report generation can spiral out of control. Mountains of paper threaten to swamp your files. Robot automates report bursting, distribution, bundling, and archiving, and offers secure, selective online report viewing. Manage your reports with the Robot Report Management Solution. Key features include:

  • FORTRAFor over 30 years, Robot has been a leader in systems management for IBM i. With batch job creation and scheduling at its core, the Robot Job Scheduling Solution reduces the opportunity for human error and helps you maintain service levels, automating even the biggest, most complex runbooks. Manage your job schedule with the Robot Job Scheduling Solution. Key features include:

  • LANSA Business users want new applications now. Market and regulatory pressures require faster application updates and delivery into production. Your IBM i developers may be approaching retirement, and you see no sure way to fill their positions with experienced developers. In addition, you may be caught between maintaining your existing applications and the uncertainty of moving to something new.

  • LANSAWhen it comes to creating your business applications, there are hundreds of coding platforms and programming languages to choose from. These options range from very complex traditional programming languages to Low-Code platforms where sometimes no traditional coding experience is needed. Download our whitepaper, The Power of Writing Code in a Low-Code Solution, and:

  • LANSASupply Chain is becoming increasingly complex and unpredictable. From raw materials for manufacturing to food supply chains, the journey from source to production to delivery to consumers is marred with inefficiencies, manual processes, shortages, recalls, counterfeits, and scandals. In this webinar, we discuss how:

  • The MC Resource Centers bring you the widest selection of white papers, trial software, and on-demand webcasts for you to choose from. >> Review the list of White Papers, Trial Software or On-Demand Webcast at the MC Press Resource Center. >> Add the items to yru Cart and complet he checkout process and submit

  • Profound Logic Have you been wondering about Node.js? Our free Node.js Webinar Series takes you from total beginner to creating a fully-functional IBM i Node.js business application.

  • SB Profound WC 5536Join us for this hour-long webcast that will explore:

  • Fortra IT managers hoping to find new IBM i talent are discovering that the pool of experienced RPG programmers and operators or administrators with intimate knowledge of the operating system and the applications that run on it is small. This begs the question: How will you manage the platform that supports such a big part of your business? This guide offers strategies and software suggestions to help you plan IT staffing and resources and smooth the transition after your AS/400 talent retires. Read on to learn: