get notified!

Mac OS X makes extensive use of a variety of event notification mechanisms, as described here. One such mechanism is documented in the notify(3) man pages, and it is these types of libnotify notifications that are the focus of this post. Notifications can be posted and observed in a global namespace across all processes (with optional access control), and in general allow a process to respond to events that occur outside the purview of the process.

One simple example would be the shutdown or restart event. When the user clicks Restart, loginwindow posts a notification called com.apple.loginwindow.restartinitiated. Various other processes who have registered to receive this notification will now know that a restart is coming (soon!). A lot of stuff begins to happen to prepare the machine for a reboot. Getting that event notification from userspace out in a timely fashion to all the various custodians who need to do work is key to the whole operation.

I see two primary use cases for such a notification system: 1) You are authoring software that creates events that others (perhaps even other parts of your own software, running in a different context) need to respond to, or 2) you wish to respond to a notification for a certain event that you know is being posted by someone else.

The first case is succinctly demonstrated by the example in the man page for notifyutil. To expand on it just a bit, and more clearly demonstrate the common case of there being some indeterminate time delta between registering for a notification and receiving it, consider this example:

Open a Terminal window. Execute:

date; notifyutil -t -1 some.pants ; say 'zomg'

Open another Terminal window, but keep the first one in view. In your mind, count to ‘d’, and then execute:

notifyutil -p some.pants

In the first window, you see that a notification for some.pants was received roughly ‘d’ seconds after the registration occured, and if your audio volume is up, you hear that Mac OS X does not know how to pronounce ‘zomg’.

The second case of responding to notifications generated by others is less obvious, since in normal operation, all of these notifications are invisible to the user. You have to know the name of a notification to register for it. The fun begins when you remember to ask the question “how do I find out what notifications are being posted?”. The answer might be obvious to anyone who read the man page! notifyd is our friend, buddy. As all this is open source, we could confirm our suspicions that notifyd probably logs to ASL, and sure enough, in notify_proc.c, we see :

log_message(ASL_LEVEL_DEBUG, "__notify_server_post %s", name);

Ok! So all we need to do is ask ASL to show us debug messages for notifyd.

sudo syslog -c notifyd -d

At this point, the messages are theoretically being sent. However, the default data store (i.e. that which you can examine with the Console app) still isn’t listening, so we also need:

sudo syslog -c syslogd -d

Next you should make a new log database query using Console:

Now you can just sit back and watch the notifications roll in! For example, if I choose Restart from the Apple menu:

__notify_server_post com.apple.loginwindow.likelyShutdown
__notify_server_post com.apple.loginwindow.restartinitiated

and then a few seconds later, after I click Cancel:

__notify_server_post com.apple.loginwindow.logoutcancelled

At this point, you should be armed with enough information to find out what events are flying around, and then attach an action of your choosing to events of interest. Have fun!

Update: you can disable the debug logging as follows:

sudo syslog -c syslogd -n
sudo syslog -c notifyd off

About dre

I like all kinds of food.
This entry was posted in development, OS X, OS X Server, scripts, tutorials. Bookmark the permalink.

One Response to get notified!

  1. Ian says:

    This appears to have changed in Lion. The tips above don’t log to Console anymore.

Leave a Reply