< Previous PageNext Page > Hide TOC

Logging Errors and Warnings

You can use two major APIs in Mac OS X to log errors: syslog and asl. In addition, you can use a number of higher-level APIs built on top of these such as NSLog. However, because most daemons are written in C, you probably want to use the low-level APIs when writing code that executes at startup.

The syslog API is the most commonly used logging API on UNIX and Linux systems. For this reason, you should consider using it when writing cross-platform software. For software specific to Mac OS X, you should use the asl API because it provides more functionality.

If your daemon uses standard output or standard error to notify users of problems during startup, those error messages are not generally visible to a user. You can, of course, boot in verbose mode (by holding down Command-v at startup), but you may have a hard time reading the errors as they scroll by. To solve this problem, you should use system logging to record error conditions for later analysis by the user or system administrator.

Contents:

Log Levels and Log Files
Logging Errors Using the syslog API
Logging Errors Using the asl API


Log Levels and Log Files

In Mac OS X (and other UNIX-based and UNIX-like operating systems), the system logger supports logging at a number of priority levels. The priority levels (and suggested uses for these levels) are:

The system logger in Mac OS X determines where to log messages at any given priority level based on the file /etc/syslog.conf.

Note: A daemon or application may mask low-priority messages before they even get to the system logger using the setlogmask function call. Thus, if you want to see these debugging messages in the system log, you may have to pass certain debugging flags to the daemon, regardless of how you have configured the system logger in /etc/syslog.conf.

Logging Errors Using the syslog API

The syslog API is relatively straightforward. It consists of five main functions:

void syslog(int priority, const char *message, ...);
void vsyslog(int priority, const char *message,
                va_list args);
void openlog(const char *ident, int logopt, int facility);
void closelog(void);
int setlogmask(int maskpri);

The first function you should call is openlog. This function associates future calls to syslog with a particular facility. You can find a list of facilities in the man page for syslog.

Note: Technically, you can call syslog without calling openlog, but as a rule, you should always call openlog to specify a facility and logging options. If you do not call openlog before you call syslog, the API will use the default facility, LOG_USER.

Next, you should call syslog. This function actually logs your message at a specified priority level. The priority levels for log messages are LOG_EMERG, LOG_ALERT, LOG_CRIT, LOG_ERR, LOG_WARNING, LOG_NOTICE, LOG_INFO, or LOG_DEBUG, in decreasing order of importance. These correspond with the levels described in “Log Levels and Log Files.”

!

Warning: It is very important to choose an appropriate priority level for log messages. The system logger discards most low-priority messages, depending on the facility specified. To find out how the system logger decides which facilities and priority levels to log in a given log file, look in the file /etc/syslog.conf.

If you need to write a wrapper function for the syslog function, you should use the function vsyslog instead. This function is identical to syslog except that it takes a variable argument list parameter instead of a series of individual parameters.

Finally, when your program exits (or when you need to specify a different facility), you should call closelog. This function resets the facility and logging options to the default settings as though you had never called openlog.

The following code example shows how to log a simple error message:

#include <fcntl.h>
#include <syslog.h>
 
main()
{
        int cause_an_error = open("/fictitious_file", O_RDONLY, 0); // sets errno to ENOENT
        openlog("LogIt", (LOG_CONS|LOG_PERROR|LOG_PID), LOG_DAEMON);
        syslog(LOG_EMERG, "This is a silly test: Error %m: %d", 42);
        closelog();
}

The flags passed to openlog specify the following:

These and other flags are described in more detail in the syslog manual page.

In addition to the usual printf format flags, this command supports an additional flag, %m. If this flag appears in the log string, it is replaced by a string representation of the last error stored in errno. This is equivalent to what would be reported if you called perror or strerror directly.

Thus, the code sample above prints the following message to standard output:

LogIt[165]: This is a silly test: Error No such file or directory: 42

Then, the code sample tells the system logger to log that message. As a result, assuming you have not changed /etc/syslog.conf, the system logger broadcasts this message to all users:

Broadcast Message from user@My-Machine-Name.mycompany.com
        (no tty) at 13:28 PDT...
 
Jul 24 13:28:46 My-Machine-Name LogIt[601]: This is a silly test: Error No such file or directory: 42

In this example, the process ID was 601, and the process name was LogIt.

For additional control over what gets logged, you can use the function setlogmask to quickly enable or disable logging at various levels. For example, the following code disables logging of any messages below the LOG_EMERG level (which is one higher than the LOG_ALERT level):

setlogmask(LOG_UPTO(LOG_ALERT));

You might, for example, use this function to disable logging of debug messages without recompiling your code or adding conditional statements.

Logging Errors Using the asl API

The asl API is short for Apple System Logger. The Apple System Logger API is very similar to syslog but provides additional functionality.

There are a few key differences, though; the asl logging API:

The following sample code is equivalent to the code in “Logging Errors Using the syslog API,” except that it uses asl for logging:

#include <fcntl.h>
#include <asl.h>
#include <unistd.h>
 
main()
{
        aslclient log_client;
        int cause_an_error = open("/fictitious_file", O_RDONLY, 0);
 
        log_client = asl_open("LogIt", "The LogIt Facility", ASL_OPT_STDERR);
        asl_log(log_client, NULL, ASL_LEVEL_EMERG, "This is a silly test: Error %m: %d", 42);
        asl_close(log_client);
}

A complete explanation of the additional features of the asl API is beyond the scope of this document. For more information, see the asl manual page.



< Previous PageNext Page > Hide TOC


© 2003, 2008 Apple Inc. All Rights Reserved. (Last updated: 2008-11-19)


Did this document help you?
Yes: Tell us what works for you.
It’s good, but: Report typos, inaccuracies, and so forth.
It wasn’t helpful: Tell us what would have helped.