This is

as days pass by, by Stuart Langridge

. Here I write about many things. In the past I wrote about other things but the past is past. I write code for people to play with, I write about my life on Twitter, and I write here.

On I wrote Storing Zeitgeist data in desktopcouch, on the subject of DesktopCouch, Zeitgeist, and Hacks.

A fun game with Seif Lotfy of the Zeitgeist project today, to answer the question: how hard would it be to have my Zeitgeist event log be in desktopcouch? That makes the logs from all my computers available on all my computers. This is increasingly important as more stuff starts going into Zeitgeist -- for example, we're going to start storing lots of Ubuntu One events in there to make what's happening with Ubuntu One on your machine more transparent and obvious, if you want to see it. So, after some conversation where Seif told me it was easy and I scoffed and bet him a beer that it wasn't...it turned out it wasn't that hard after all.

Zeitgeist has extensions. These aren't brilliantly documented yet, but you can drop a Python file into .local/share/zeitgeist/extensions and if it's got the right sort of class in it then that class will get run as a part of Zeitgeist. Extensions are great for doing things like running some code every time there's an event which goes into Zeitgeist. /usr/share/zeitgeist/_zeitgeist/engine/extensions/blacklist.py is an example extension.

However, we didn't do it quite that way. Because we're taking an action on every event in zeitgeist, we don't want to slow the core down. So instead of actually being an extension that's built into the main Zeitgeist process, we're an extension which launches a separate subprocess. The subprocess uses ZeitgeistClient to get notified whenever any event happens, and then serialises that event into desktopcouch. Basically, it's an event-driven loop driven by ZeitgeistClient.install_monitor, so every time a new event happens our function gets called, and that function serialises the event into a desktopcouch Record and saves it.

The other half of the equation is getting events from desktopcouch. Obviously, if you've got more than one machine, then sometimes events that happened on the other machine will arrive here, and you need to pull those new records out of desktopcouch, turn then back into event objects, and push them into the Zeitgeist engine. The way to do this efficiently is by monitoring desktopcouch's changes feed. The changes feed is a core part of CouchDB itself; the way it works is that you open an HTTP connection to it and that connection lives forever; whenever a record changes or is added or deleted to the database you're monitoring, a line (actually, a JSON description) about the change is printed to that HTTP connection. So you just watch that feed forever, and whenever you get told "this record has changed", you go fetch that record from desktopcouch in the normal way and then do whatever you want with it. Nicely event-driven; no polling at all, no wakeups if you don't need them.

Getting at the changes feed from a desktopcouch database is a little more complex than getting at it from a server CouchDB, but it's doable, and one of the things we plan to do in the Ubuntu 11.04 development cycle is make this trivial to do: you'll just call databaseobject.glib_callback_for_changes(my_callback_function) and your callback will be called every time there's a change in the database. (The code below contains a load of complex OAuth stuff to derive a validated URL for the _changes feed; that's what we're going to wrap up in that one line.)

I was pretty pleased to see how simple it is to interact with Zeitgeist, and I plan for us to work more with the Zeitgeist team. Thanks especially to Seif who talked me through a lot of this, and to whom I owe a pint or something.

desktopcouch_gateway.py; drop it in .local/share/zeitgeist/extensions, and then restart the Zeitgeist server with zeitgeist-daemon --replace.

Steve J

I think the link to the Zeitgeist project is http://zeitgeist-project.com/ (not .org as it is in the text)

sil

Steve J: quite right, and corrected; thanks :)

Beton

It work's on my maverick machine (after installing gir1.0-soup-2.4 package), but on my lucid machine it doesn't work (even with gir1.0-soup-2.4 installed). Any idea why? Here's the traceback:

b3t0n@megas:~$ zeitgeist-daemon --replace

DEBUG:root:Checking for another running instance...

DEBUG:root:No running instances found.

INFO:zeitgeist.sql:Using database: /home/b3t0n/.local/share/zeitgeist/activity.sqlite

DEBUG:zeitgeist.sql:Core schema is good. DB loaded in 2.59494781494ms

DEBUG:zeitgeist.extension:Searching for system extensions in: /usr/share/zeitgeist/_zeitgeist/engine/extensions

DEBUG:zeitgeist.extension:Searching for user extensions in: /home/b3t0n/.local/share/zeitgeist/extensions

Traceback (most recent call last):

File "/usr/bin/zeitgeist-daemon", line 98, in

interface = RemoteInterface(mainloop = mainloop)

File "/usr/share/zeitgeist/_zeitgeist/engine/remote.py", line 53, in __init__

self._engine = get_engine()

File "/usr/share/zeitgeist/_zeitgeist/engine/__init__.py", line 43, in get_engine

_engine = main.ZeitgeistEngine()

File "/usr/share/zeitgeist/_zeitgeist/engine/main.py", line 120, in __init__

default_extensions = get_extensions()

File "/usr/share/zeitgeist/_zeitgeist/engine/extension.py", line 147, in get_extensions

extensions = _scan_extensions()

File "/usr/share/zeitgeist/_zeitgeist/engine/extension.py", line 193, in _scan_extensions

ext = __import__(name)

File "/home/b3t0n/.local/share/zeitgeist/extensions/desktopcouch_gateway.py", line 35, in

from gi.repository import Soup

ImportError: No module named gi.repository

sil

Beton: I think you'll need python-gobject as well.

Beton

It's already installed. From Lucid's repo (2.21.1-0ubuntu3)

Ted Gould

So I think this is interesting, but I think that there should be separate documents for the Zeitgeist data from each machine. This would allow Zeitgeist to say "the documented you edited on your laptop" which I think is more interesting than just aggregating the data together.

sil

Beton: does /usr/share/pyshared/gtk-2.0/gi/repository/__init__.py exist?

Ted: there are, in fact, separate documents; each event on each machine gets its own document. So what you're looking for is done :)

Beton

Nope, it doesn't.

sil

Beton: aha. I think this stuff might require Ubuntu 10.10, I'm afraid; it has the newer Gtk and Python GObject introspection work in it.

This website belongs to Stuart Langridge. Contact details are available. Don't eat yellow snow. Valid HTML5, at least in theory, except for the bits that aren't because I'm that futuristic that I'm ahead of the spec, oh yes. HTML5 help from Bruce Lawson, among others. Fonts from the superb FontSquirrel. End.