Automatic Log Rotation in Mac OS X

Log rotation is a standard practice to ensure that log files are periodically restarted so that they don’t grow without bounds.  In the past, when disk space was at a premium and maximum file sizes were limited, this was an absolute necessity.  For more modern systems, these constraints may be less relevant although they may continue to be a valid concern for very active systems or with verbose logging enabled.  Even with abundant disk space, appropriate managing of the system logs helps ensure the system remains healthy, logs remain available for diagnostics and analysis, and operational overhead is reduced.

In Linux, the typical log rotation utility is, appropriately enough, logrotate.  However, Mac OS X uses a different tool, newsyslog, to manage the log rotation responsibilities.  This utility is run automatically by the OS at frequently intervals and evaluates the rules defined in its configuration file — /etc/newsyslog.conf.  For the log files defined in the config, it can evaluate the need to rotate based on a number of criteria, such as file size, at a specific time, at a specific interval, etc.  It can also specify additional actions to take on the rotated log, including compression of the old log, maintaining a fixed number of previous log files, setting appropriate permissions, etc.  Full documentation is available in the man page for newsyslog.conf.

Each entry in the newsyslog.conf file is specified as a single line with space-delimited fields for the various options.  The general format is as follows (with [] surrounding the optional fields):

logfilename [owner:group] mode count size when flags [/pid_file] [sig_num]

An example entry for rotating the named.stats log file can be specified as follows:

/var/log/named.stats                    640  5     1000 *     J

In the above example, the full path is specified for the target log file — /var/log/named.stats.  Permissions (640) are specified in the typical Unix manner, in this case enabling read/write for the owner and read-only for the group.  This log file will maintain a maximum of 5 files, removing the oldest file as newer archived logs are created.  This log file is also set to rotate at a fixed size — 1000 kilobytes and can rotate at any time (“*”) this size threshold is exceeded.  The “J” flag specified calls for the the older log files to be compressed (further reducing used disk space) using the bzip2 utility.

A special note for binary (not text-based) logs:  by default, newsyslog will inject a line at the beginning of a file indicating when and why the log rotated.  For most text-based logs, this can be easily skipped over but for binary logs this might result in an unreadable file.  In this case, be sure to specify the “B” flag which suppresses the informational line from being injected.

Enable Remote Logging on Mac OS X

Background

It is often desirable to collect the system logs from various devices onto a central “logging host”.  This can simplify monitoring needs considerably as tools and scripts need only work on a single host.  It also provides some security benefits as hackers will have a harder time masking their activities if they do not have access to the logging host.

On Mac OS X, there is a logging daemon (the Unix standard syslogd utility) that can be used to write both local logs and receive logs from remote hosts.  Unfortunately, the ability to receive remote logs is turned off in the default installation.  However, it is a trivial task to enable this functionality.

Setup (for 10.5 and older systems)

  1. Login as administrator to the logging host
  2. Open a terminal session using the Terminal utility
  3. Navigate to the LaunchDaemons directory
    cd /System/Library/LaunchDaemons
  4. Edit the com.apple.syslogd.plist file
    sudo vi com.apple.syslogd.plist
  5. Remove the comment delimiters (<!-- and -->) surrounding the NetworkListener block and save the changes
    <!--
     <key>NetworkListener</key>
     <dict>
     <key>SockServiceName</key>
     <string>syslog</string>
     <key>SockType</key>
     <string>dgram</string>
     </dict>
    -->
  6. Stop the currently running instance of the syslog daemon
    sudo launchctl unload /System/Library/LaunchDaemons/com.apple.syslogd.plist
  7. Restart the syslog daemon to pick up the changes in the LaunchDaemon configuration
    sudo launchctl load /System/Library/LaunchDaemons/com.apple.syslogd.plist

The logging facility on the log host should now be available for remote devices to use.

Setup (for 10.6 and later systems)

  1. Login as administrator to the logging host
  2. Open a terminal session using the Terminal utility
  3. Navigate to the LaunchDaemons directory
    cd /System/Library/LaunchDaemons
  4. Convert the com.apple.syslogd.plist to XML format
    sudo plutil -convert xml1 com.apple.syslogd.plist
  5. Edit the com.apple.syslogd.plist file
    sudo vi com.apple.syslogd.plist
  6. Add the NetworkListener dict entry after the end of the BSDSystemLogger dict entry and save the changes
    <key>NetworkListener</key>
    <dict>
    <key>SockServiceName</key>
    <string>syslog</string>
    <key>SockType</key>
    <string>dgram</string>
    </dict>
  7. Convert the com.apple.syslogd.plist file back to the binary format
    sudo plutil -convert binary1 com.apple.syslogd.plist
  8. Stop the currently running instance of the syslog daemon
    sudo launchctl unload /System/Library/LaunchDaemons/com.apple.syslogd.plist
  9. Restart the syslog daemon to pick up the changes in the LaunchDaemon configuration
    sudo launchctl load /System/Library/LaunchDaemons/com.apple.syslogd.plist

The logging facility on the log host should now be available for remote devices to use.

Setup (using the Property List Editor)

Apple provides the Property List Editor utility as part of its developer tools.  The developer tools are usually a separate install from the operating system and is frequently not installed on systems.  If it is present, then using the Property List Editor may be the most convenient means of modifying the com.apple.syslogd.plist file.

  1. Login as administrator to the logging host
  2. Launch the Property List Editor utility (typically located in /Developer/Applications/Utilities)
  3. Open the /System/Library/LaunchDaemons/com.apple.syslogd.plist file
  4. Select the “Sockets” dictionary entry and “Add Item” to create a new key in the “Sockets” dictionary
  5. Change the name of the item to “NetworkListener” and set its type to “Dictionary”
  6. Select the “NetworkListener” dictionary entry and “Add Item” to create a new key in the “NetworkListener” dictionary
  7. Change the name of the item to “SockServiceName”, its type to “String” and its value to “syslog”
  8. Select the “NetworkListener” dictionary entry and “Add Item” to create another new key in the “NetworkListener” dictionary
  9. Change the name of the item to “SockType”, its type to “String”, and its value to “dgram”
  10. Save the file and quit the Property List Editor utility.  The property list should resemble the following example:Example Property List for com.apple.syslogd.plist
  11. Open a terminal session using the Terminal utility
  12. Navigate to the LaunchDaemons directory
    cd /System/Library/LaunchDaemons
  13. Stop the currently running instance of the syslog daemon
    sudo launchctl unload /System/Library/LaunchDaemons/com.apple.syslogd.plist
  14. Restart the syslog daemon to pick up the changes in the LaunchDaemon configuration
    sudo launchctl load /System/Library/LaunchDaemons/com.apple.syslogd.plist

Extending Service Discovery Cabilities on ReadyNAS

Background

The ReadyNAS appliance can advertise the services available on their system through the Bonjour or UPnP protocols.  These service discovery protocols can greatly simplify the client connection and configuration problems.  The web administration interface provides an easy method of controlling some of the services advertised, but there may be additional services running on the ReadyNAS that do not have an administrative interface for controlling their advertisement.

Because the ReadyNAS uses the open-source project avahi to handle service discovery, documentation on extending the list of services to be advertised is readily available.  With this information, it is relatively easy to create new service records for additional services and simplify the user experience.

Setup

In order to create additional avahi service records, it is necessary to enable root SSH access to the ReadyNAS system.

The service file is a simple XML file which defines a service-group record.  The service-group record contains a number of elements which may vary according to the service being advertised.  The two essential elements are the name record, which defines the displayed name for the service in question, and the service record, which defines the type, port, and any other connection-related information.

The name element has one possible attribute – replace-wildcards – which can take a value of “yes” or “no”.  If the attribute is present and the value is “yes”, then a %h can be used in the value which will be automatically substituted with the host name of the system.

The service element groups together the necessary information for service connectivity.  The two most essential elements it contains are the type element and the port element.  The type is the is the official service type as defined by RFC 2782 and the port is simply the listening port number.

Depending on the service, there may be additional elements or attributes that are necessary to have a properly formatted service file.  Be sure to consult the documentation to ensure the service is properly defined before making any changes.

Example

The following is an example configuration that enables service discovery for SSH:


<?xml version="1.0" standalone='no'?>
<service-group>
<name replace-wildcards="yes">SSH on %h</name>
<service>
<type>_ssh._tcp</type>
<port>22</port>
</service>
</service-group>

To activate this service, perform the following actions:

  1. Login (via ssh) as “root” to the ReadyNAS appliance.
  2. Navigate to the configuration directory.

    cd /etc/avahi/services

  3. Create a new file named ssh.service containing the configuration information listed above.
  4. Restart the avahi service to load the new service file.

    kill -SIGHUP `ps ax | grep avahi | grep -v grep | awk '{ print $1 }'`