Skip to Content
Author's profile photo Former Member

Perl and SAP Adventures, Part 3

I’m sure that all seasoned Basis Administrators have had instances where critical errors have shown up in the system log and an alert on this would have saved them countless hours and accumulated issues.  Well, I’ve had that, too.  In my case, at one point in time I had to support an interface that was particularly problematic.  It consisted of a background job that would connect to a system half-way around the world, and network issues would often cause that connection to fail and the background job to hang.  When this happened, we would see errors in the system log such as “Communication Error, CPIC return code xxx” at which time the interface job would need to be killed and manually restarted, and quickly!  If it did not get restarted before the next execution 2 hours later, then they would step on each other’s toes, and life would not be good.

My solution for this was to write a script that would scan the system log and search for these tell-tale signs that would alert the on-call support person that the job needed manual intervention.  I had thoughts about eventually putting in the logic to restart the job as well, but the job was replaced with a less problematic version before I could do so.

This blog will take the simple script written in Perl and SAP Adventures, Part 2 and expand on it for that very purpose.  We’ll take each of the servers brought back from the TH_SERVER_LIST function module, and read the system log from that server.

Searching for a function module to read the system log, I find SXMI_XMB_SYSLOG_READ.  This function module is a part of the XMB Interface, which is a collection of function modules SAP has written to provide eXternal Management Basics, for example to third-party tool vendors.  There are other such interfaces, such as XBP for managing batch jobs, and XOM for Output Management.

It took me a long time to figure this out in the beginning, and it involved finding PDF files on sapnet, but to use one of these function modules, you have to first execute another function module to log on to the interface you wish to utilize.  This is simple enough, but the problem that arises from this is it is not easy to test these function modules from SE37, and, as mentioned in my previous blog, I find it good practice to test all function modules first to make sure they’re going to give me what it is I’m looking for.  If you attempt to test a function module that requires such an interface logon, then the testing of the function module will simply yield the results:

Exception       NOT_LOGGED_ON

Which is not very helpful.  I have no solution for this at this time, but in this case continued to write the script to attempt to get what I needed, hoping the function module would work for me, and it did.

So, given this, the basic program flow needs to look something like this:

  1. Log on to SAP
  2. Enumerate the available servers
  3. Log on to XMB interface
  4. Read each server’s system log
  5. Log off from XMB interface
  6. Log off from SAP

So the first thing we’ll do is to log on to the SAP system and get the list of available server names (name meaning hostname_SID_SysNr).  I won’t cover that in much detail, since it was the subject of my previous blog, but you’ll notice that I’ve added a bit to the code, to insert the server names into an array for later retrieval.  Additionally, I’ve added a trim function to remove leading and trailing spaces, and I trim the server name returned from the function module.  If you notice in my previous blog, each of the server names has several spaces at the end (noticeable only if you highlight the text).  If we leave these spaces in, they’ll get passed along to the function module to read the system log, and it won’t recognize the server names as valid.

The next part is to log on to the XMB interface.  The log on process looks like this:

### Log on to the XMB Interface
my $rca = $rfc->function_lookup("SXMI_LOGON");
my $xln = $rca->create_function_call;
$xln->EXTCOMPANY('TWDC');                      # this is a name of your choosing
$xln->EXTPRODUCT('RFCTEST');                   # this is a name of your choosing
$xln->INTERFACE('XMB');                        # this is one of the valid interfaces
$xln->parameter('VERSION')->value('0.1');      # this version must coincide with the interface
print "Session ID: ".$xln->SESSIONID." ";     # this line is informational only

Your script has to pass the EXTCOMPANY parameter, which is a name of your choosing.  Additionally, EXTPRODUCT is also something that you define.  These parameters are designed to denote a third-party company’s product information.  The INTERFACE is one of the valid SAP interfaces, which must coincide with the correct VERSION.  (You may notice that VERSION must be passed differently than the others, as it is a reserved word in perl – thanks to Piers for alerting me to that)  You can then only execute function modules from the interface you have logged on to.  Valid INTERFACE/VERSION combinations in my ECC 6.0 system, as of this writing, are:
XMB 0.1
XBP 2.0
XOM 0.1
XAL 1.0
XMW 1.0

In my previous blog, I covered how to read data from a structure (table) provided by a function module.  Here we see the other type of data a function module can provide, which is a single value you’ll find in the EXPORTING section of the code header.  In this case, the SXMI_LOGON function module contains the following:

*"       EXPORTING

So you can see that we’ve retrieved and printed the exported value for SESSIONID in the following manner:

print "Session ID: ".$xln->SESSIONID."

This line is not required, but including it lets us know that we’ve logged on to the interface successfully, by virtue of the fact that we’ve been assigned a session id.  Of course, if the logon is not successful, you should see an error, so it’s really your choice whether to leave this line in your script.

Now to the meat of the script, which is to read the system log from each application server.  It’s really very easy, and is done with the following code:

for my $x (0 .. $#server) {                    # we're looping through each of the server names here
    my $rcc = $rfc->function_lookup("SXMI_XMB_SYSLOG_READ");
    my $slr = $rcc->create_function_call;
    $slr->SERVER_NAME($server[$x]);            # passing in the current server name from the loop
    $slr->EXTERNAL_USER_NAME('GOOFY');         # this does not have to be a user in the SAP system
                                               # SYSLOG_TBL is the structure we're reading from
    foreach my $row (@{$slr->SYSLOG_TBL}) {    # it contains a hash with only one key/value pair, the key
        print trim($row->{'LINE'})." ";       # for which is called simply LINE, and the value is 255 characters long
    }                                          # even if it is less than 255 chars, it will be padded with spaces on the
}                                              # end, which is why I'm using this trim function to remove trailing spaces

Notice that I have provided a value for EXTERNAL_USER_NAME.  This is not a valid name in the SAP system, it’s simply a name that a third party product would pass to identify who is using that product, so you can make something up here.  Also, using the default values for the SXMI_XMB_SYSLOG_READ function module, it will only read the last ten minutes of each server’s system log.  So this script would be designed to be run every ten minutes from a scheduler (like cron, for instance), or the default from and to values would have to be overridden to expand the length of time.

After this loop to read the system log of each server, we’ll log off of the XMB interface and disconnect from the SAP system.  The log off process is simple, you can see it in the script.

Here is the script in its entirety:

#!/usr/bin/perl -w
use strict;
use sapnwrfc;
my $srvcnt = 0;
my @server = ();
my $rfc = SAPNW::Rfc->rfc_connect;

### Enumerate the list of available servers
my $rcb = $rfc->function_lookup("TH_SERVER_LIST");
my $tsl = $rcb->create_function_call;
foreach my $row (@{$tsl->LIST}) {
    $srvcnt ++;

### Log on to the XMB Interface
my $rca = $rfc->function_lookup("SXMI_LOGON");
my $xln = $rca->create_function_call;

print "Session ID: ".$xln->SESSIONID." ";

### For each app server, read its system log
for my $x (0 .. $#server) {
    my $rcc = $rfc->function_lookup("SXMI_XMB_SYSLOG_READ");
    my $slr = $rcc->create_function_call;

    foreach my $row (@{$slr->SYSLOG_TBL}) {
        print trim($row->{'LINE'})." ";

### Log off of the XMB Interface
my $rcd = $rfc->function_lookup("SXMI_LOGOFF");
my $xlf = $rcd->create_function_call;


### trim function, to remove leading and/or trailing spaces
sub trim {
        my @OUT = @_;
        for (@OUT) {
        return wantarray ? @OUT : $OUT[0];

And, when executed, it will print out the system log for each application server in the system, similar to this:

System Log: Local Analysis of apsrv002 for apsrv019_RQA_00         1
|From date/time............. 06/19/2009 / 13:56:23|
|To date/time............... 06/19/2009 / 14:06:23|
|                                                 |
|User.......................                      |
|Transaction code...........                      |
|Terminal................... *                    |
|Task / Number..............                      |
|Problem class..............                      |
|Instance....................                     |
|Further restrictions.......                      |
|Sorted ? ................ SOFI                   |
|Pages with single entries 00000080               |
|With statistics............                      |
|                                                 |

System Log: Local Analysis of apsrv002 for apsrv019_RQA_00         2

Date : 06/19/2009
|Time    |SAP instance   |User    |Program |Priority|Grp|N|Text                                                                  |
|13:57:01|apsrv019_RQA_00|USERJ001|RM06XB00|        |R2 |C|Terminal 00220 in status DISC                                         |
|13:57:01|apsrv019_RQA_00|USERJ001|RM06XB00|        |R4 |7|Delete session 001 after error 004                                    |
|13:57:01|apsrv019_RQA_00|        |        |        |Q0 |G|Request (type DIA) cannot be processed                                |
|14:05:59|apsrv019_RQA_00|        |        |        |Q0 |4|Connection to user 26452 (USERA033 ), terminal 251 (desktop1-001) lost|

Number of records read......... 0000002895
Number of records selected..... 0000000004
Old records skipped............ 0000002891
Further selection:
Number of records read......... 0000000004
Number of records selected..... 0000000004
Number of records printed...... 0000000004
End of system log
System Log: Local Analysis of apsrv002 for apsrv019_RQA_00         3
C o n t e n t s
|Content           |Page|        Start      |   End             |
|Selection criteria|  1 |                   |                   |
|                  |  2 |06/19/2009 13:57:01|06/19/2009 14:05:59|
|Contents          |  3 |                   |                   |
End of program

In the Perl and SAP Adventures, Part 4, we’ll take it just a bit further and make this script actually useful by giving it the ability to search the system log for relevant text, and send an alert if found.

Assigned Tags

      You must be Logged on to comment or reply to a post.
      Author's profile photo Mingzuo Shen
      Mingzuo Shen
      works as usual.

      Use sxml_versions_get to get the names and versions.
      That is left as an exercise for the reader!

      use strict;
      use warnings;
      use sapnwrfc;
      my $interface = shift;
      SAPNW::Rfc->load_config; # load the connection parameters defined in sap.yml
      my $rfc = SAPNW::Rfc->rfc_connect;
      # SE37 display function module
      my $rcb = $rfc->function_lookup("SXMI_VERSIONS_GET");
      my $tsl = $rcb->create_function_call;
      if (defined $interface && length($interface)> 0) {
      print "SXMI interfaces and versions\n";
      foreach my $row (@{$tsl->VERSIONS}) {
         print $row->{'INTERFACE'}, ' ', $row->{'VERSION'}, "\n";

      perl sxmi_versions_get.perl
      SXMI interfaces and versions
      XBP 3.0
      XMB 0.1
      XOM 0.1
      XAL 1.0

      perl sxmi_versions_get.perl XMB
      SXMI interfaces and versions
      XMB 0.1

      Author's profile photo Former Member
      Former Member
      Blog Post Author
      That's an excellent addition, thanks!  I struggle sometimes with how much information to give in the article, since I don't want to make it 18 pages long.  🙂

      BTW, my list of interfaces and versions returned from an ECC 6.0 system is the same as yours, which doesn't include XMW, which I listed in the blog.  Interesting that this doesn't get returned, but if you use SXMI_LOGON, it is a valid interface, and you can actually use any version number you wish with it.  I'm not sure why that is, as I haven't tried to use this interface, and so haven't looked into it yet.


      Author's profile photo Former Member
      Former Member
      You'll get a LOGON_DENIED message unless you have the following authorizations for the RFC user.

      ID INTERFACE = *