Debugging launchd Daemons in macOS: Enabling Comprehensive Logging for Troubleshooting


2 views

When troubleshooting launchd issues on macOS (including legacy systems like 10.6 Snow Leopard), it's crucial to understand that launchd doesn't maintain traditional log files like /var/log/launchd.log. Instead, it integrates with Apple's unified logging system (introduced in later versions) or syslog in older systems.

For macOS 10.6, you'll need to modify the system configuration:

# Create or edit the launchd debug plist
sudo defaults write /Library/Preferences/com.apple.launchd Debug -bool true

# Alternatively, for user-specific agents:
defaults write $HOME/Library/Preferences/com.apple.launchd Debug -bool true

After enabling debugging, check these locations:

# System-wide logs (requires root)
sudo tail -f /var/log/system.log

# For more detailed output:
sudo syslog -w | grep launchd

When your daemon returns status 1, follow this diagnostic approach:

# First check the basic status
launchctl list | grep your.daemon.label

# Then examine stderr/stdout if configured in plist:
<key>StandardOutPath</key>
<string>/tmp/yourdaemon.stdout</string>
<key>StandardErrorPath</key>
<string>/tmp/yourdaemon.stderr</string>

For persistent issues, consider these methods:

  1. Run the daemon executable directly from command line to see raw output
  2. Check file permissions on both the plist and executable
  3. Verify all required environment variables are set
  4. Examine dependencies with otool -L for native binaries

Here's a complete troubleshooting example for a failing backup daemon:

# Enable debugging
sudo defaults write /Library/Preferences/com.apple.launchd Debug -bool true

# Reload the daemon
sudo launchctl unload /Library/LaunchDaemons/com.example.backup.plist
sudo launchctl load /Library/LaunchDaemons/com.example.backup.plist

# Monitor logs in real-time
sudo syslog -w | grep -E 'backupd|launchd'

Common findings might include permission issues ("Operation not permitted"), missing dependencies, or environment configuration problems.


Unlike traditional Unix systems, macOS handles system logging through the unified logging system since OS X 10.12. For earlier versions like 10.6 you're using, launchd logs can be found in:

/var/log/system.log
/var/log/launchd.log

For troubleshooting a daemon with status code 1 (which typically indicates a general error), we need to enable more verbose logging.

Create a special plist configuration file to increase logging verbosity:

sudo defaults write /Library/Preferences/com.apple.launchd LogLevel -string debug

Then restart launchd to apply changes:

sudo launchctl kickstart -k system/com.apple.launchd

For temporary debugging during development, you can redirect stdout/stderr to files in your plist:

<key>StandardOutPath</key>
<string>/tmp/mydaemon.stdout</string>
<key>StandardErrorPath</key>
<string>/tmp/mydaemon.stderr</string>

When debugging a Python-based launchd service that fails with status 1:

#!/usr/bin/env python
import sys
import logging

logging.basicConfig(
    filename='/tmp/mydaemon.log',
    level=logging.DEBUG,
    format='%(asctime)s %(levelname)s %(message)s'
)

try:
    # Your daemon code here
    logging.info("Service started successfully")
except Exception as e:
    logging.error(f"Service failed: {str(e)}")
    sys.exit(1)

Use these commands to check service status and recent logs:

launchctl list | grep your.daemon.identifier
sudo log show --predicate 'sender == "launchd"' --last 1h

For legacy systems (10.6 specifically), check kernel messages too:

dmesg | grep launchd