Sending Messages from RPG to a Syslog Server

Article ID: 58195

I was sitting here struggling to find a new and exciting topic for this week's newsletter when I received an email from a colleague who wanted to write log entries from RPG to a Syslog server. He said it was hard to find information and wanted to know if I had worked with it.

As luck would have it, I have in fact worked with Syslog. I had not previously thought of using it as a way of logging messages from an RPG program, but why not?

Syslog is the logging tool originally used in Unix environments. In addition to ordinary computers, many of today's network appliances also support Syslog, and that has made Syslog ubiquitous. Better yet, Syslog can send its log entries in realtime over a network to another server. This lets you consolidate your logs because all your applications and network appliances can write their logs to a common server. Instead of having to log on and check the logs of dozens (or even hundreds) of individual machines, you can check them all together in one place.

It makes perfect sense to me that RPG business applications might want to write log entries to Syslog as well--so this article shows you how.

SYSLOGR4--an RPG Tool for Syslog

I've written an RPG service program named SYSLOGR4 as a native RPG tool for writing Syslog messages. This tool writes messages only to a Syslog server--in other words, it's a client application not a server application. For the purposes of this article, I'll assume you already have a Syslog server available running on another computer somewhere. However, if you'd like me to demonstrate writing a Syslog server for IBM i, please send that suggestion to tips@scottklement.com.

My SYSLOGR4 client has three different procedures:

  • Syslog_Open() — is called at the start of your program to designate the server you'd like to send your log entries to.
  • Syslog_Write() — is called each time you want to log something.
  • Syslog_Close() — is called at the end of your program to free up the resources that were reserved by Syslog_Open.

In our business, we've written ordering and inventory systems. When a customer has an order that needs to be filled, we generate a picking slip that tells a worker where to go in the warehouse to get the items to be placed on the customer's order. Let's say now, for the sake of example, that I wanted to log every order that's picked using Syslog. I'd modify my picking program by adding the following at startup:

      /copy syslog_h

     D lm              s               *

      /free
         lm = syslog_open('logMaster.klements.com');

This code doesn't do much, except verify that logMaster.klements.com is a valid host name and set it up as the host that will receive log entries. No connection is made to the logging server at this time; it just gets the program ready.

Now, somewhere deep in my picking code, the user chooses an order to pick and tells the computer to find the inventory to ship on the order. If I want to log that start via Syslog(), I'd code something like this:

          .
          .
         syslog_write( lm: LOG_LOCAL0: LOG_INFO
                     : 'User ' + %trim(User) + ' has begun picking '
                     + 'order ' + %char(OrderNo));
          .
          .

This will log a message saying, "User KLEMSCOT has begun picking order 54321," and the message will be logged using the LOG_LOCAL0 facility, and it will be logged at LOG_INFO severity.

Finally, at the end of the program, when it's time to close everything, my program will call syslog_close() as follows:

         syslog_close(lm);

Facility Code

The second parameter to syslog_write() is the facility code. The facility code is intended to identify the type of application generating the message. It lets you group applications into logical groupings for log files. For example, you might want to put all log messages that relate to email into the same log file, and all log messages relating to inventory control might go into a separate log file.

The Syslog specification states that the following facilities are available:

     D LOG_KERN        C                   0
     D LOG_USER        C                   1
     D LOG_MAIL        C                   2
     D LOG_DAEMON      C                   3
     D LOG_AUTH        C                   4
     D LOG_SYSLOG      C                   5
     D LOG_LPR         C                   6
     D LOG_NEWS        C                   7
     D LOG_UUCP        C                   8
     D LOG_CRON        C                   9
     D LOG_AUTHPRIV    C                   10
     D LOG_FTP         C                   11
     D LOG_NTP         C                   12
     D LOG_SECURITY    C                   13
     D LOG_CONSOLE     C                   14
     D LOG_CLOCK       C                   15
     D LOG_LOCAL0      C                   16
     D LOG_LOCAL1      C                   17
     D LOG_LOCAL2      C                   18
     D LOG_LOCAL3      C                   19
     D LOG_LOCAL4      C                   20
     D LOG_LOCAL5      C                   21
     D LOG_LOCAL6      C                   22
     D LOG_LOCAL7      C                   23

Most of these codes correspond to applications that are widely used on Unix, such as LOG_MAIL (email) and LOG_UUCP. However, some of them are less specific. For example, LOG_AUTH is related to any sort of authority messages. LOG_SECURITY is for security items, such as firewall messages on a network. These concepts apply to the IBM i as well as they would for any other computer system.

For messages that don't relate to the predefined facilities such as email, security, and authority, there are facilities named LOG_LOCALx. These "local" facilities are intended for applications that are "local" to your enterprise--in other words, they are general-purpose codes that programmers can use for their own applications. For my example, I decided LOG_LOCAL0 would be for my picking application.

On the Syslog server, it can be configured to write messages for the local0 facility to their own log file. For example, it might log them to /var/log/picking.log so that anyone wanting to review the inventory log could look in that file.

Severity Code

The third parameter to syslog_write() is the severity code.

The severity code is intended to describe how critical or urgent the message is. The possible severity codes are as follows:

     D LOG_EMERG       C                   0
     D LOG_ALERT       C                   1
     D LOG_CRIT        C                   2
     D LOG_ERR         C                   3
     D LOG_WARNING     C                   4
     D LOG_NOTICE      C                   5
     D LOG_INFO        C                   6
     D LOG_DEBUG       C                   7

They stand for emergency, alert, critical, error, warning, notice, information, and debug, respectively. When you configure a Syslog server, you can tell it which types of information to log and which types to ignore. So you might want LOG_ERR and LOG_CRIT to be written to a log file, while configuring LOG_EMERG and LOG_ALERT to send text messages to your phone or to at least send a direct message to you if you're logged on.

When writing software, it makes sense to log a ton of stuff by using the LOG_DEBUG facility. Any piece of information you might ever need when troubleshooting the application could be logged under LOG_DEBUG. Don't worry about cluttering up the logs, because the syslog facility can be configured to save only certain severity levels. For example, under normal production operation, you might have the server configured to log severities only from LOG_WARNING to LOG_EMERG. Therefore, anything marked with LOG_DEBUG, LOG_INFO, or LOG_NOTICE would be ignored. However, suppose you have one of those oddball problems in production that nobody can explain? When that happens, you change the syslog server to log/save all log entries. Then wait until the problem reoccurs, and you'll find that you have lots of diagnostics to use to determine the problem. Once the problem has been fixed, you can put the logging level back to where you started.

How Does It Work?

Under the covers, Syslog is sending UDP datagrams on port 514. UDP is a protocol that runs on a TCP/IP network; however, it deals with sending individual packets. So the data you send has to fit within the packet size of a UDP datagram on your network. For example, Ethernet has 1500-byte packets, but part of that 1500 bytes is used for Ethernet meta information as well as IP meta information. The resultant data size will have a maximum length of somewhere around 1,400 characters. Other networks have smaller packet sizes, some limiting you to as little as 500 characters per log entry. My recommendation is to keep your log entries short--that way your application is more likely to log successfully over the TCP/IP networks of the future.

The data in the UDP packet will look like this (in ASCII):

<134>Jun 24 05:02:06 MYCOMPUTERNAME User KLEMSCOT has begun picking order 54321

The part that says <134> is where the facility and severity are sent over the network. This number is created by multiplying the facility by 8 and then adding the severity. I have 134 because LOG_LOCAL0 is the number 16, and LOG_INFO is the number 6. 16 x 8 = 128, and when you add 6, you get 134.

The facility/severity code is followed by the timestamp. The timestamp is a little weird in that Syslog's timestamps do not contain a year! Apparently Syslog just assumes that the messages are all from the current year.

The timestamp is followed by the hostname of the sending computer. If no hostname can be found, it uses the IP address.

Finally, everything that comes after the hostname is the message to be logged.

Code Download

Download my SYSLOGR4 service program that provides Syslog support in RPG.

ProVIP Sponsors

ProVIP Sponsors