Array
(
[body] => Array
(
[#value] => <p>To mark my sixth
anniversary of writing for NaSPA, I decided to revisit my first article and
revamp it for a new audience. This
article examines how one site incorporated one of the features of their change
management system with the features of their dump analysis tool to help
applications programmers determine the cause of development and production
abends.</p>
<h2>Introduction</h2>
<p>When an abend
occurs during a production batch run, an application programmer can determine
the offending instruction by using a variety of actions and tools. Some application programmers try to determine
what went wrong by recompiling a program to obtain a listing that contains the
offset of the code in error. Usually the
compile is done in a test environment (possibly with "home grown" JCL
and compile options), but pointing to the production source and copy libraries. Sometimes application programmers, having
attended a vendor training session for a product, continue to use the sample
compile deck long after the class is over.
Unfortunately, copy members may have been modified between the time the
program was put into production and the time the abend occurs. This leads to ambiguous results in tracking
down the offending instruction, which is not desirable when a production batch
cycle is waiting to be restarted.</p>
<p>This article
describes how I provided one method of handling these abend situations by using
one product to support another. The
application programmers at this site now have a "fast path" to obtain
the compile listing and begin their program analysis. Consequently, any down-time from production
abends can be substantially reduced.
Similarly, development time is improved with faster problem resolution.</p>
<h2>Background</h2>
<p>I recently
worked with a major insurance company in the New York City metropolitan area on a significant
enterprise-wide project. A significant
portion of the application programming staff was provided by offshore-based
consulting firms, and the majority of the staff was located in India.
It was my belief that the application programmers could have used the
site's existing software tools more effectively to reduce, and then eliminate,
the error-prone possibilities inherent in program development and subsequent
recompilations. </p>
<p>This site had
been using CA's Endevor for many years as its mainframe change management
system. Endevor, by default, keeps the
last compile listing (in a proprietary compressed form) before a program is
installed in production. My goal was to
use the Endevor compressed listing to provide as much information as possible
and to drive the abend detection process.</p>
<p>The site was also
using IBM's Fault Analyzer to perform dump analysis; this product had replaced
Compuware's Abend-AID several years ago.
However, few application programmers, if any, were aware of the
product. None of them, to my knowledge,
realized they needed a side file to help them; nor did they understand how easy
it was to create one.</p>
<p>While the IBM
product literature describes a step that can be used to create a side file when
a program is compiled, this was not part of the Endevor process. I was not about to try to convince anyone in
the Change Management group to modify the compile process to include an extra
step for a "third-party product."
However, there was nothing to prevent the use of this utility after the
compile was completed. Just the same,
this utility requires specific compile-time options. The obvious factor was to ensure all of the
required Fault Analyzer compile options were included with the Endevor
compile. That way, the post-processor
could write the appropriate records to the side file. </p>
<p>Tangential to my
overall project responsibilities, I developed an ISPF dialog to assist the
application programmers. The design of
the data entry panel is very straightforward.
Using as few fields as possible, application programmers enter the name
of the program, indicate their Endevor system and subsystem (which identifies
the compressed listing data set), and specify whether the program is batch or
online. A batch job is submitted to
process the files.</p>
<h2>The ISPF Dialog</h2>
<p>The ISPF dialog helps
application programmers to perform a key, and potentially time-consuming,
function with greater ease; that is, detect errors in program abends,
irrespective of whether the program is in development or production. It is accomplished by using the Endevor
compressed listing that is saved at the completion of a successful compile.</p>
<p>The dialog
submits a batch job that extracts the compressed listing from the production
library (or, for development, from the current Endevor compile) and uses an IBM
utility to create the appropriate side file for diagnosing the cause of an
abend.</p>
<p>To access the
dialog, application programmers navigate through a series of ISPF options. A panel, similar to the one shown in Figure
1, is displayed. Almost all of the
fields on the panel are required. After
the Enter key is pressed, a batch job is submitted to process the information. A message is displayed that indicates the
name of the side file into which the records are placed, and reminds the
application programmer of the specific Fault Analyzer option to use.</p>
<p><span class="inline left"><img src="http://www.naspa.com/system/files/images/NDVRDBUG.img_assist_custom.jpg" alt="Figure 1" title="Figure 1" class="image img_assist_custom" width="399" height="299" /><span class="caption" style="width: 397px;"><strong>Figure 1</strong></span></span> </p><p>Figure 1:
Endevor - Fault Analyzer data entry panel</p>
<h2>An Overview of the Batch Processing</h2>
<p>Here's a brief
overview of what takes place within the batch job.</p>
<p>The preliminary
steps delete and then allocate the working partitioned data sets required in
the job. Because the batch stream only
processes one member at a time, there was no design requirement to use the
features of a PDS/E. One file contains
the output from the compressed listing, while the other contains the output of
the Fault Analyzer utility (the side file).</p>
<p>Another step
takes the Endevor compressed listing and expands it, as shown in Figure 2. This is done using a standard CA-supplied
Endevor utility program. It simply uses
SCL to identify the input file name (the compressed listing data set), the
output file name (the temporary partitioned data set), both of which are coded
in the JCL, and the program name to be expanded.</p>
<p> </p>
<div class="codeblock"><code>//* <br />//JS030 EXEC PGM=NDVRC1,PARM='BC1PNCPY' <br />//CONLIB DD DISP=SHR,DSN=SYSPROD.ENDEVOR.LOADLIB <br />//COMPLIST DD DISP=SHR,DSN=&amp;NDVRCLST <br />//PDSLIST DD DISP=OLD,DSN=&amp;MYNDVRDS <br />//SYSPRINT DD SYSOUT=* <br />//BTSERR DD SYSOUT=* <br />//SYSUDUMP DD SYSOUT=D<br />//SYSIN DD * <br /> COPY INPUT DDNAME=COMPLIST <br /> OUTPUT DDNAME=PDSLIST<br /> UNPACKED<br /> UPDATE IF PRESENT MEMBER=&NDFAPPGM<br />/*</code></div>
<p>Figure 2:
Abridged batch routine that expands Endevor compressed listing</p>
<p>The next step
invokes an ISPF Edit macro to edit the expanded listing file and reformat it.</p>
<p>Another step
invokes the Fault Analyzer utility to read the listing, parse the contents, and
place the output into the appropriate side file.</p>
<p>After the batch
job completes, the programmer can view the source within Fault Analyzer by
using the appropriate IDIOPTS statements.</p>
<h2>The Batch Job Details</h2>
<p>Now that you
know what goes on in the job, we can take a closer look at the details.</p>
<p>The abridged JCL
to execute this job is shown in Figure 3.
This example depicts the processing for a batch COBOL program. Let's look at what is going on in each of
these steps.</p>
<p> </p>
<div class="codeblock"><code>//JS050 EXEC PGM=IKJEFT01 <br />//SYSPROC DD DISP=SHR,DSN=SYSUSER.ISPF.ISPCLIB <br />// DD DISP=SHR,DSN=SYSPROD.OEM.ISPCLIB <br />//ISPPLIB DD DISP=SHR,DSN=SYSPROD.IBM.ISPPLIB <br />//ISPMLIB DD DISP=SHR,DSN=SYSPROD.IBM.ISPMLIB <br />//ISPSLIB DD DISP=SHR,DSN=SYSPROD.IBM.ISPSLIB<br />//ISPTLIB DD DISP=(OLD,PASS),DSN=*.JS040.CPYOUT2 <br />// DD DISP=SHR,DSN=SYS1PROD.IBM.ISPTLIB <br />//ISPTABL DD DUMMY <br />//ISPLOG DD DUMMY <br />//ISPPROF DD DISP=(OLD,PASS),DSN=*.JS040.CPYOUT1 <br />//SYSTSPRT DD SYSOUT=* <br />//SYSUDUMP DD SYSOUT=D <br />//SYSPRINT DD DUMMY <br />//MESSAGES DD SYSOUT=* <br />//SYSIN DD DUMMY<br />//SYSTSIN DD *<br /> ISPSTART CMD(%EMACASEQ &MYNDVRDS(&NDFAPPGM) NDVRDBG1 &DEBUG)</p><br />//* <br />//JS060 EXEC PGM=IDILANGX,PARM='&NDFAPPGM (COBOL ERROR '<br />//LISTING DD DISP=SHR,DSN=&amp;MYNDVRDS <br />//IDILANGX DD DISP=SHR,DSN=&amp;NDFAPSDS <br />//SYSUDUMP DD SYSOUT=D <br />//* <br />//*--------------------------------------------------------<br />//* CHECK TO SEE IF MEMBER NAME MATCHES PROGRAM-ID <br />//*--------------------------------------------------------<br />//* <br />//JS070 EXEC PGM=IKJEFT1A,PARM='NDVRDBG2&DEBUG&'<br />//SYSPROC DD DISP=SHR,DSN=SYSUSER.ISPF.ISPCLIB <br />// DD DISP=SHR,DSN=SYSPROD.OEM.ISPCLIB <br />//SYSTSPRT DD SYSOUT=* <br />//MESSAGES DD SYSOUT=* <br />//SYSTSIN DD DUMMY <br />//NDVRINFI DD * <br />)TBA 10 <br />&NDFAPPGM!&MYNDVRDS&NDFAPSDS <br />/* <br />//*</code></div>
<p>Figure 3:
Abridged batch job to process compressed listing and create side file</p>
<p>The job's fifth
step invokes ISPF in batch mode. The
REXX ISPF Edit macro NDVRDBG1 is invoked to edit the expanded compressed
listing of the program. I will discuss
the details of this processing in the following section.</p>
<p>The sixth step
invokes the IBM utility, IDILANGX, which reads the COBOL listing file and
writes the appropriate records to the Fault Analyzer side file.</p>
<p>The seventh step
invokes another ISPF Edit macro to verify that the member name matches the
PROGRAM-ID in the COBOL program. This is
to ensure that Fault Analyzer can process the side file correctly. If the names do not match, the Edit macro
renames the side file member name to the PROGRAM-ID.</p>
<h2>The REXX Exec</h2>
<p>The abridged
code from the Edit macro, shown in Figure 4, performs validations on the data
in the listing, and creates a file that is capable of being read by the
post-processor.</p>
<p>/* Get rid of
everything before the start of the compile listing */</p>
<p> 'Find "Invocation
parameters" '
</p>
<p> '(<a href="/freelinking/CurLine">CurLine</a>) = <a href="/freelinking/LineNum">LineNum</a> .ZCsr' </p>
<p> If <a href="/freelinking/CurLine">CurLine</a> > 2 Then Do </p>
<p> 'Label '<a href="/freelinking/CurLine">CurLine</a>-2' = .Here' </p>
<p> 'Del .ZFirst .Here' </p>
<p> End
</p>
<p>/* Get rid of
everything after the end of the compile listing */</p>
<p> 'Find "End of compilation"
' </p>
<p> '(<a href="/freelinking/CurLine">CurLine</a>) = <a href="/freelinking/LineNum">LineNum</a> .ZCsr' </p>
<p> '(<a href="/freelinking/LineLast">LineLast</a>) = <a href="/freelinking/LineNum">LineNum</a> .ZLast' </p>
<p> If <a href="/freelinking/LastLine">LastLine</a> -2 > <a href="/freelinking/CurLine">CurLine</a> Then
Do </p>
<p> 'Label '<a href="/freelinking/CurLine">CurLine</a>+2' = .Here' </p>
<p> 'Del .Here .ZLast' </p>
<p> End
</p>
<p>/* Build a
string of all options used to compile the program */</p>
<p> 'Find "Options "
First' /* always start of parms */</p>
<p> '(<a href="/freelinking/CurLine">CurLine</a>) = <a href="/freelinking/LineNum">LineNum</a> .ZCsr' </p>
<p> <a href="/freelinking/LineFrst">LineFrst</a> = <a href="/freelinking/CurLine">CurLine</a> + 1 </p>
<p> 'Find "ZWB" ' /* always last parm
*/</p>
<p> '(<a href="/freelinking/LineLast">LineLast</a>) = <a href="/freelinking/LineNum">LineNum</a> .ZCsr' </p>
<p> Do i = <a href="/freelinking/LineFrst">LineFrst</a> to <a href="/freelinking/LineLast">LineLast</a> </p>
<p> '(<a href="/freelinking/DataLine">DataLine</a>) = Line 'i /* dot (.) is used as a delimiter */</p>
<p> If Pos('5655-G53',<a href="/freelinking/DataLine">DataLine</a>) > 0
Then /* Enterprise COBOL */</p>
<p> Iterate
</p>
<p> If Left(<a href="/freelinking/DataLine">DataLine</a>,1) = 0 Then </p>
<p> <a href="/freelinking/DataLine">DataLine</a> =
Word(<a href="/freelinking/DataLine">DataLine</a>,2)
</p>
<p> strCobOp = strCobOp || '.' ||
Strip(Left(<a href="/freelinking/DataLine">DataLine</a>,25)) </p>
<p> End
</p>
<p> strCobOp = strCobOp || '.' /* here's
where we get the last .*/</p>
<p>/* Determine if
there are any options that will not work... */</p>
<p> Do i = 1 to strOpt.0 </p>
<p> If Pos(strOpt.i,strCobOp) = 0 Then
Do </p>
<p> strEFlag = 'Yes' </p>
<p>
j = j + 1 </p>
<p> Notify.j = strEMsg4
Strip(strOpt.i,'B','.') </p>
<p> End
</p>
<p> End </p>
<p> If Pos('.LIST.',strCobOp) = 0 Then
Do </p>
<p> If Pos('.OFFSET.',strCobOp) = 0
Then Do </p>
<p> strEFlag = 'Yes' </p>
<p> j = j + 1 </p>
<p> Notify.j = strEMsg5 </p>
<p> End
</p>
<p> End </p>
<p> </p>
<p>Figure 4: Abridged
REXX ISPF Edit macro that processes the expanded Endevor compressed listing</p>Let's review
what is going on in this Edit macro:
<ul><li>All of the compressed listing data
surrounding the COBOL compiler listing is removed.</li><li>Because this is designed for COBOL
programs, all of the compile-time options are placed into a single
"dot-delimited" variable (as opposed to an array), for easy
searching.</li><li>The known list of required Fault
Analyzer options is compared to this variable. If any of the required options is not
found, an error message is issued. However,
all of the variables are still checked.</li><li>The file is saved.</li></ul>
<p>If an error
message is generated by this routine, the output is placed in the ddname,
MESSAGES. A note in the SYSPRINT (and
emphasized in the ISPF dialog's tutorial) directs application programmers to
review this file.</p>
<p>After the batch
job completes, the application programmer can launch Fault Analyzer and
establish the appropriate set of options to analyze the abend. He or she can immediately begin problem
determination by reviewing the exact line of code at which the program abended.</p>
<h2>Conclusion</h2>
<p>By incorporating
the features of one product with the features of another, a higher degree of
consistency has been achieved. I was
able to take the existing, unused Endevor output file and turn it into a
constructive input file for application programmers to use with Fault Analyzer.</p>
<p>This ISPF dialog
lets application programmers focus on problem resolution, not on the need to
recreate a program listing. By using
this solution, application programmers are assured that they are working with a
compile listing that matches the load module executing in the production (or
development) environment. This results
in a better use of programmer time - especially during a middle of the night
production abend - and particularly if it affects the batch stream's critical
path.</p>
<p>Application
programmers who use this facility appreciate that they have a compile listing
that matches their program. They do not
have to worry that their compile deck is using invalid compile options,
back-level system data sets, or outdated copy books. They can be more productive in a matter of a
few minutes, using the program products that are available.</p>
<p><em>NaSPA member Larry Kahm is president of Heliotropic Systems, Inc., an
IBM Business Partner located in Fort Lee, NJ. He has 20 years of experience
working with systems and application programmers, vendors, and management to
ensure that business applications are developed, maintained, and enhanced with
the appropriate set of tools. When not training to run in the ING NYC Marathon,
he's busy helping clients with their office networks and home computers.</em></p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<p> </p>
<br class="clear" />
[#weight] => 0
)
[adsense_start] => Array
(
[#value] => <!-- google_ad_section_start -->
[#weight] => -1
)
[adsense_end] => Array
(
[#value] => <!-- google_ad_section_end -->
[#weight] => 1
)
[field_author] => Array
(
[#weight] => -4
[#value] => <div class="field field-type-text field-field-author"><div class="field-items"><div class="field-item"><div class="field-label-inline-first">Author: </div>Larry Kahm</div></div></div>
[#access] => 1
)
[field_description] => Array
(
[#weight] => -2
[#value] =>
[#access] =>
)
[field_article_pdf] => Array
(
[#weight] => -1
[#value] =>
[#access] =>
)
[field_item_type] => Array
(
[#weight] => 9
[#value] =>
[#access] =>
)
[field_article_cost] => Array
(
[#weight] => 10
[#value] =>
[#access] =>
)
[field_temppdf] => Array
(
[#weight] => 10
[#value] =>
[#access] =>
)
[fivestar_widget] => Array
(
[#value] => <form action="/node/4333/render" accept-charset="UTF-8" method="post" id="fivestar-form-node-4333" class="fivestar-widget">
<div><input type="hidden" name="content_type" id="edit-content-type" value="node" />
<input type="hidden" name="content_id" id="edit-content-id" value="4333" />
<div class="form-item">
<label>Your vote: </label>
<div class="fivestar-widget container-inline fivestar-average-text fivestar-user-stars"><input type="hidden" name="auto_submit_path" id="edit-auto-submit-path" value="/fivestar/vote/node/4333" class="fivestar-path" />
<div class="form-item">
<label class="option"><input type="radio" name="vote" value="20" class="form-radio fivestar-average-text fivestar-user-stars" /> 1</label>
</div>
<div class="form-item">
<label class="option"><input type="radio" name="vote" value="40" class="form-radio fivestar-average-text fivestar-user-stars" /> 2</label>
</div>
<div class="form-item">
<label class="option"><input type="radio" name="vote" value="60" class="form-radio fivestar-average-text fivestar-user-stars" /> 3</label>
</div>
<div class="form-item">
<label class="option"><input type="radio" name="vote" value="80" class="form-radio fivestar-average-text fivestar-user-stars" /> 4</label>
</div>
<div class="form-item">
<label class="option"><input type="radio" name="vote" value="100" class="form-radio fivestar-average-text fivestar-user-stars" /> 5</label>
</div>
</div><div id="fivestar-summary-4333" class="description"><div class="fivestar-summary-empty">No votes yet</div></div>
</div>
<input type="submit" name="op" id="edit-submit" value="Submit rating" class="form-submit fivestar-submit" />
<input type="hidden" name="form_id" id="edit-fivestar-form-node-4333" value="fivestar_form_node_4333" />
</div></form>
[#weight] => 50
)
[forward] => Array
(
[#value] => <form action="/node/4333/render" accept-charset="UTF-8" method="post" id="forward-form">
<div><fieldset class=" collapsible collapsed"><legend>Forward this page to a friend</legend><div class="form-item">
<label for="edit-yemail">Your Email: <span class="form-required" title="This field is required.">*</span></label>
<input type="text" maxlength="256" name="yemail" id="edit-yemail" size="58" value="" class="form-text required" />
</div>
<div class="form-item">
<label for="edit-yname">Your Name: <span class="form-required" title="This field is required.">*</span></label>
<input type="text" maxlength="256" name="yname" id="edit-yname" size="58" value="" class="form-text required" />
</div>
<div class="form-item">
<label for="edit-recipients">Send To: <span class="form-required" title="This field is required.">*</span></label>
<textarea cols="50" rows="5" name="recipients" id="edit-recipients" class="form-textarea resizable required"></textarea>
<div class="description">Enter multiple addresses on separate lines or separate them with commas.</div>
</div>
<div class="form-item">
<label>Message Subject: </label>
(Your Name) has forwarded a page to you from NaSPA.com
</div>
<div class="form-item">
<label>Message Body: </label>
(Your Name) thought you would like to see this page from the NaSPA web site.
</div>
<div class="form-item">
<label for="edit-message">Your Personal Message: <span class="form-required" title="This field is required.">*</span></label>
<textarea cols="50" rows="10" name="message" id="edit-message" class="form-textarea resizable required"></textarea>
</div>
<input type="hidden" name="nid" id="edit-nid" value="4333" />
<input type="hidden" name="forward_footer" id="edit-forward-footer" value=" " />
<input type="submit" name="op" id="edit-submit" value="Send Message" class="form-submit" />
</fieldset>
<input type="hidden" name="form_id" id="edit-forward-form" value="forward_form" />
</div></form>
[#weight] => 10
)
[links_related] => Array
(
[#value] =>
[#weight] => 1
)
[vote_up_down] => Array
(
[#value] => <div class="vote-up-down-widget"><span class="up-inact" title="You must login to vote."></span><span class="down-inact" title="You must login to vote."></span></div>
[#weight] => -10
)
)