System Logging

Body

The system logging capabilities in BeOS are built on top of the syslog interface as defined by the POSIX standard. In addition to the functionality provided by that standard, it has some BeOS specific extensions.

The following article will give an overview about how this service works internally in Haiku, and how it can be used in applications. The implementation as done in Haiku might differ from the actual implementation in BeOS, but it is fully binary compatible.

The syslog_daemon

The syslog service is provided by a standard BApplication that runs as a server in the background, the syslog_daemon.

After it has been started during the system's boot process, it will just sit there and wait for messages. Every call to syslog() or log_thread/team() will pass a message to the server containing information about what should be written to the log and with what options. The message is not a BMessage, but a plain data structure that can be created without any knowledge about BMessages. That is needed, because the service is used by the kernel as well.

The server then just passes on that message to its internal handlers. It has two built-in handlers. One of them just processes the message and dumps a formatted text to the syslog file at /var/log/syslog. The other one creates a standard BMessage out of the message and broadcasts it to all of its listeners. However, how you can communicate with the syslog_daemon to get those messages will be the topic of another newsletter article.

If the syslog file reaches a certain size (512 kB), it will be renamed to syslog.old, and a new syslog file is created.

Using the system logger

As already mentioned, the system logging capabilities are accessible via the standard POSIX functions. Therefore, the syslog.h header is placed in the headers/posix directory, and the functions are implemented in libroot.so. That's already different from standard BeOS where you need to link against libbe.so to access that functionality. The syslog.h header can be found in the headers/be/support directory on a standard BeOS system.
The implementation and header have been moved to simplify porting of POSIX-compliant applications; however, that neither breaks binary nor source compatibility (as long as you haven't used "#include <support/syslog.h>" for your native Be apps.)

Logging sessions

The first call of a function that will connect to the syslog service will create a syslog session. It's important to know that there is one session for each thread that uses the service, as well as one extra session for all team-wide logging functions.

The original POSIX API as well as part of the additional BeOS API both use thread specific sessions. When a session is started, it will inherit the options defined for the team session. That means you can set logging options that every thread in your application will respect (if you don't overwrite them locally). But in order to define team wide options, you have to specifically use the BeOS-specific team API.

Team functions

  • void openlog_team(const char *ident, int logopt, int facility)

    Sets the team logging options for the other team functions and for inherited sessions.

    • ident is the identification string that prepends every message from your team.
    • logopt allows you to set several logging options (see below).
    • facility determines from what facility your message has been sent; for your standard issues, this should just be LOG_USER.

     

  • void closelog_team(void)

    Closes the current session. This has currently no effect for the team logging functions.

  • void log_team(int priority, const char *message, ...)

    Sends a message of the specified priority to the syslog daemon.

  • int setlogmask_team(int priorityMask)

    Use the LOG_MASK() macro to build a mask of priorities to show. All messages of other priorities will be discarded. Example uses:

     setlogmask_team(LOG_MASK(LOG_WARNING));
      // all messages of priority LOG_WARNING will be shown
     setlogmask_team(LOG_MASK(LOG_ERR + 1) - 1);
      // all messages with a priority level higher than LOG_ERR will be shown

Thread functions

The POSIX API and the thread specific Be API behave exactly in the same way; the *_thread() functions just clobber the global namespace :). All calls except for the closelog() calls will start a new session if there is none yet, and will inherit the current team logging options if they do.
  • void openlog_thread(const char *ident, int logopt, int facility)
    void openlog(const char *ident, int logopt, int facility)

    Sets the log options for the current thread.

  • void closelog_thread(void)
    void closelog(void)

    Closes the thread session, and frees all associated data. The next call to the syslog service will start a new session, and will inherit the team log options at that point again.

  • void log_thread(int priority, const char *message, ...)
    syslog(int priority, const char *message, ...)

    Sends a message of the specified priority to the syslog daemon.

  • int setlogmask_thread(int priorityMask)
    setlogmask(int priorityMask)

    Use the LOG_MASK() macro to build a mask of priorities to show. All messages of other priorities will be discarded.

Logging options for openlog()

These are the options that can be passed to openlog()/openlog_thread()/openlog_team(). Note, its effects might be depending on the syslog listener; for example, for a GUI syslog viewer, LOG_PID might have no effect at all.
  • LOG_PID
    log the process (thread/team) ID with each message
  • LOG_CONS
    if the message cannot be delivered to the syslog daemon, it will be directly dumped to stderr.
  • LOG_PERROR the message will not only be sent to the syslog daemon, it will also be written to the application's stderr, not only if sending fails like LOG_CONS.
There are some more flags defined, but they have currently no effect (notably, LOG_ODELAY, LOG_NDELAY, LOG_NOWAIT and LOG_SERIAL).

Playing with the Haiku implementation

The server is implemented in current/src/servers/syslog_daemon, naturally, you have to build and start it, before it'll work - although you can also check out the syslog functionality without a living server.

To test the syslog functionality, you can use the provided test program. You'll find it in current/src/tests/kernel/libroot/posix/SyslogTest.cpp. Edit it as you please, and you'll get a good idea of how it works.

Differences between the Haiku and the BeOS implementations

As already written some paragraphs above, the implemenation has been moved from libbe.so to libroot.so. But since all applications are linked against libroot.so anyway, this won't have any impact on binary compatibility.

The header file syslog.h has been moved to the headers/posix directory, where all other POSIX headers reside. If you've previously used the full path of the old header ("#include <support/syslog.h>"), you might encounter errors when trying to compile your old code. The issue has not been finally decided on, but it probably won't change in the release version of our headers.

It has not been tested if the thread logging functions inherit their settings from the team session on R5 or not, and if this mechanism works similarly if it's in place.

The only other known difference is that our syslog_daemon implements a way to broadcast the messages to a listener application. But as I already said earlier, this will be the topic of another newsletter article. Also note that the actual implementation of that protocol has not been finalized yet and is probably subject to change; your shiny system logger viewer might need to be updated before we reach R1.

References

There is a brief introduction to the BeOS system logger at http://www.beatjapan.org/mirror/www.be.com/aboutbe/benewsletter/Issue61.html . You can also find a description of the standard POSIX syslog functions at http://www.opengroup.org/onlinepubs/007904975/functions/closelog.html .