QAUJRN is the system's audit journal that captures various pieces of information that you want it to. A friend has a job that uses the Display Journal command, DSPJRN, to retrieve the data from QAUDJRN.
01 DSPJRN JRN(QSYS/QAUDJRN) RCVRNG(*CURCHAIN) + 02 FROMTIME(&FROMTIME) TOTIME(&TOTIME) + 03 ENTTYP(AF) + 04 OUTPUT(*OUTFILE) OUTFILE(SOMELIB/JRN_AF) |
One day his job errored, and he reached out to me for help as it returned an error he had never seen before. He sent me the job log, and I found the following within it:
CPF7053 Escape 40 MM/DD/YY 11:30:00.444197 QJODSPJE QSYS 0698 QSECAUDR Message . . . . : Values for RCVRNG parameter not correct; reason code 4. 4 - There are more than the maximum number of allowed receivers in the receiver chain for the operation being performed. The maximum supported number is 2045. |
Checking IBM's documentation for the DSPJRN command's RCVRNG parameter it explains:
Range of journal receivers (RCVRNG) Note: If the maximum number of receivers (2045) in the range is surpassed, an error occurs, and no journal entries are converted. |
How do we find how many QAUDJRN journal receivers there are?
I went to the SQL View JOURNAL_INFO with the following statement:
01 SELECT JOURNAL_NAME AS "Journal", 02 ATTACHED_JOURNAL_RECEIVER_LIBRARY AS "Rcvr lib", 03 NUMBER_JOURNAL_RECEIVERS AS "No. rcvrs" 04 FROM QSYS2.JOURNAL_INFO 05 WHERE JOURNAL_NAME = 'QAUDJRN' |
Lines 1 – 3: I have given the columns shorter column headings as their names, especially the second one, are very long.
Line 5: I have not bothered to give a library as there can only be one QAUDJRN, and it is found in the library QSYS.
The results were:
Journal Rcvr lib No. rcvrs ------- --------- --------- QAUDJRN QGPL 2085 |
There are more journal receivers, 2085, than the command's maximum allowed value, 2045.
How do I get a list of those journal receivers? I used the JOURNAL_RECEIVER_INFO View:
01 SELECT JOURNAL_NAME AS "Journal", 02 JOURNAL_RECEIVER_LIBRARY AS "Rcvr lib", 03 JOURNAL_RECEIVER_NAME AS "Rcvr name", 04 DATE(ATTACH_TIMESTAMP) AS "Attached", 05 DATE(DETACH_TIMESTAMP) AS "Detached", 06 STATUS 07 FROM QSYS2.JOURNAL_RECEIVER_INFO 08 WHERE JOURNAL_NAME = 'QAUDJRN' 09 ORDER BY "Attached" |
Lines 1 – 5: I have given the columns new column heading to make them easier to show below.
Lines 4 and 5: I only need to know the date from these timestamps, therefore, I have used the DATE scalar function to convert the timestamp values to dates.
Line 6: This is whether the receiver is attached, online (unsaved), or saved.
Line 9: Notice how I use the column heading in the Order by clause.
I am not going to show all of the results, just the first and last few:
Journal Rcvr lib Rcvr name Attached Detached Status ------- -------- ---------- ---------- ---------- -------- QAUDJRN QGPL AUDRCV0001 2022-04-15 2022-04-15 SAVED QAUDJRN QGPL AUDRCV0002 2022-04-15 2022-05-17 SAVED QAUDJRN QGPL AUDRCV0003 2022-04-17 2022-05-18 SAVED QAUDJRN QGPL AUDRCV2083 2025-11-05 2025-11-08 ONLINE QAUDJRN QGPL AUDRCV2084 2025-11-08 2025-11-12 ONLINE QAUDJRN QGPL AUDRCV2085 2025-11-12 <NULL> ATTACHED |
Now I have identified all the QAUDJRN journal receivers, I consulted my friend to establish the rules for deleting the journal receivers.
- They have been saved
- They are older than 18 months
Fortunately those are parameters in the DELETE_OLD_JOURNAL_RECEIVERS procedure:
01 CALL SYSTOOLS.DELETE_OLD_JOURNAL_RECEIVERS( 02 DELETE_OLDER_THAN => CURRENT_DATE - 18 MONTHS, 03 JOURNAL_RECEIVER_LIBRARY => 'QGPL', 04 JOURNAL_RECEIVER => 'AUDRCV%', 05 PREVIEW => 'YES') |
Line 2: This is where I say that I only want to delete journal receivers that are older than 18 months.
Line 3: All of the QAUDJRN journal receivers are in the library QGPL.
Line 4: All of their names start with "AUDRCV", the percent sign ( % ) acts as the wildcard symbol.
Line 5: I strongly recommend that you start in Preview mode to make sure you have selected the journal receivers you want to delete. If you do not use Preview mode you might accidentally delete journal receivers before you are ready to do so.
I am not going to show the results of this statement as the results are the same as those from JOURNAL_RECEIVER_INFO.
I am not going to want anyone to execute the DELETE_OLD_JOURNAL_RECEIVERS procedure, where Preview = no, more than once. It makes sense to have a program that does this, that can be added to the job scheduler. I decided to write an RPG program that looks like:
01 **free 02 ctl-opt main(Main) option(*srcstmt) ; 03 dcl-proc Main ; 04 exec sql CALL SYSTOOLS.DELETE_OLD_JOURNAL_RECEIVERS( 05 DELETE_OLDER_THAN => CURRENT_DATE - 18 MONTHS, 06 JOURNAL_RECEIVER_LIBRARY => 'QGPL', 07 JOURNAL_RECEIVER => 'AUDRCV%', 08 PREVIEW => 'NO') ; 09 return ; 10 end-proc ; |
Line 1: I have not said for some time in my posts, if you are writing RPG in 2025 you need to be using totally free RPG.
Line 2: Another thing you should be doing in modern RPG is not using the RPG cycle. The way to "turn off" the RPG cycle is to have a main procedure. And that is followed by my favorite control option.
Line 3: Start of the Main procedure.
Line 5: Delete journal receivers that are more than 18 months old.
Line 6: All of the journal receivers for the QAUDJRN journal receivers are in the library QGPL.
Line 7: All of journal receiver's names start with "AUDRCV".
Line 8: Preview is "NO", therefore, the journal receivers that conform to the selection criteria are deleted.
After the program was compiled I called it. When preview is no a file is created in QTEMP called QDLTJRNRCV. Every time the procedure tries to delete a journal receiver a row is inserted into the file documenting whether the deletion was successful or not.
When the program finished I used the following statement to see the results of the deletions.
01 SELECT DELETE_JOURNAL_RECEIVER_RESULT, 02 JOURNAL_RECEIVER_LIBRARY, 03 JOURNAL_RECEIVER_NAME 04 FROM QTEMP.QDLTJRNRCV |
Line 1: To check the success of the deletions I can look at DELETE_JOURNAL_RECEIVER_RESULT.
Lines 2 and 3: The journal receivers' library and name.
I am only showing the first few results:
DELETE_ JOURNAL_ JOURNAL_ JOURNAL_ RECEIVER_ RECEIVER_ RECEIVER_ RESULT LIBRARY NAME --------- --------- ---------- SUCCESS QGPL AUDRCV0001 SUCCESS QGPL AUDRCV0002 SUCCESS QGPL AUDRCV0003 |
When this program was run on my friend's partition more than one thousand journal receivers were deleted, and the storage utilization decreased by 13%. This is a good example of why deleting old and unwanted things is a good task to perform regularly.
I need to mention this too. I no longer use the DSPJRN command to get data from journals. I use the SQL DISPLAY_JOURNAL table function as I think it is easier to use and is more flexible than DSPJRN.
For many of the QAUDJRN entry types there are specific SQL table functions, AUDIT_JOURNAL_XX (there are now more table functions than those listed in the linked post), that allow me to extract just that entry type's data. For example:
01 SELECT * 02 FROM TABLE(SYSTOOLS.AUDIT_JOURNAL_AF( 03 STARTING_TIMESTAMP => CURRENT TIMESTAMP - 7 DAYS)) |
My preference would be be to use the Audit Data Mart, to extract and retain this data.
01 CALL QSYS2.MANAGE_AUDIT_JOURNAL_DATA_MART( 02 JOURNAL_ENTRY_TYPE => 'AF', 03 DATA_MART_LIBRARY => 'SOMELIB', 04 STARTING_TIMESTAMP => '*CONTINUE', 05 DATA_MART_ACTION => 'ADD') |
Even using my DSPJRN alternatives does not remove the need to delete old QAUDJRN journal receivers.
This article was written for IBM i 7.6, and should work for some earlier releases too.


No comments:
Post a Comment
To prevent "comment spam" all comments are moderated.
Learn about this website's comments policy here.
Some people have reported that they cannot post a comment using certain computers and browsers. If this is you feel free to use the Contact Form to send me the comment and I will post it for you, please include the title of the post so I know which one to post the comment to.