I’ve just added print job failure alert messages to the system-config-printer applet, and this is what one looks like. Part of the work involved in doing this was to switch from repeatedly polling the CUPS server for the entire job list (which can be slow and resource-intensive) to using IPP notifications to find out what’s changed.
Using IPP notifications
The API for this provided by pycups is fairly straightforward, and follows the IPP model:
- createSubscription, where you specify which IPP events you are interested in, and get given a subscription ID,
- getNotifications, where you provide your list of subscription IDs and sequence numbers, and get given a list of events, and
- cancelSubscription, where you provide your subscription ID.
Each subscription has a lease time, after which the subscription is automatically cancelled. (Hmm, I ought to add renewSubscription, seeing as there is an IPP operation for it that CUPS supports…) Here is an example of an event:
'notify-text': u'Job stopped due to filter errors; please consult the error_log file for details.',
This shows where you get the sequence number (“notify-sequence-number”) for keeping track of which events you’ve already seen, the event name (“notify-subscribed-event”, in this case “job-stopped”), and also shows what looks like a really useful field: notify-text, where it says exactly what went wrong with the job.
Unfortunately, this “Job stopped due to filter errors” string is given to us untranslated. Even if we have set the attributes-natural-language field to show that we can only understand French, we’ll get exactly the same string. Not only that, but it’s not a particularly helpful message anyway — if you don’t know much about CUPS, or how your computer does what it does, being told about something called error_log isn’t much good.
Anyway, the possibilities for that string are fairly limited. In the applet, I get it to look for “filter errors” and “backend errors”, leading to these translatable strings:
- “There was a problem processing document `%s’ (job %d).” for filter errors
- “There was a problem sending document `%s’ (job %d) to the printer.” for backend errors
- “There was a problem printing document `%s’ (job %d).” for anything else.
To try to be helpful in this situation, I’ve added a “Diagnose” button. This fires up the trouble-shooter to try to find out what the problem is.
Still to do: make the trouble-shooter allow callers to pre-select which printer is having problems.
Remote IPP jobs
All of the above only works for locally printed jobs. This is because local jobs use the IPP backend, which does not relay enough information from the remote CUPS instance to be useful even for discovering that a job has failed, let alone giving any indication of why it has failed.
Yes, that’s right, you read that correctly: if a remote CUPS job has failed, there is no indication from the local CUPS that it is the case. Instead, the job still shows locally as “Processing”. This is because the IPP backend does not stop itself when the remote job stops, and so the local “job” (i.e. the IPP backend watching the remote job) is still running.
The only thing that can give a clue as to whether the remote job is even running at all is to watch the printer-state-message attribute, which might say something like “foomatic-rip failed” — but there is no way to distinguish an error message from, say, a progress report.
Still, job failure reports for local printers only is better than nothing.