Viele Ubuntu-User wissen gar nicht, dass ihnen der Zeitgeist-Daemon heimlich über die Schulter schaut und ihre Desktop-Aktionen mitprotokolliert. Einige Perl-Skripte bereiten die Lauscherberichte auf und bringen interessante Tatsachen über die Usergewohnheiten ans Tageslicht.
Woher weiß eigentlich der Nautilus-Browser, welche Dateien ein Ubuntu-User in letzter Zeit bearbeitet hat, um sie in der Sparte »Recent« anzuzeigen? In Abbildung 1 listet er zum Beispiel zwei Screenshots auf, die ich kurz vorher zu Kontrollzwecken mit dem Fotoviewer Eye Of Gnome (»eog« ) angesehen habe.
Da Nautilus und Eye of Gnome zwei völlig getrennte Applikationen sind, die untereinander keine Daten austauschen, hilft auf dem Ubuntu-Desktop ein inoffizieller Mitarbeiter namens »zeitgeist« dabei, Spitzeldaten zu übermitteln. Interessierte können ihn mit
ps aux | grep zeitgeist
in der Prozessliste als unter ihrer User-ID laufend enttarnen. Gnome-Applikationen stehen über den Dbus mit dem Zeitgeist-Daemon in Verbindung, der relevante Vorgänge neugierig in eine Datenbank protokolliert und dort interessierten Anwendungen, zum Beispiel dem Nautilus-Browser, zur Verfügung stellt.
Als Format für die mitgeschnittenen Desktop-Events nutzt Zeitgeist eine SQlite-Datenbank, die jeder Perl-Schnüffler ebenfalls auslesen und auswerten kann. Wer dem Daemon dabei zuschauen möchte, wie er vom Desktop eintrudelnde Ereignisse aufschnappt, kann ihn mit
zeitgeist-daemon -r --log-level=DEBUG
im Debug-Modus starten, wobei der Aufruf wegen der Option »-r« auch gleich den bereits laufenden Daemon stoppt und ihn durch den im Vordergrund gestarteten ersetzt.
Unklare Zukunft
Das Zeitgeist-Projekt auf Launchpad [2] scheint allerdings seit 2013 im Dornröschenschlaf zu schlummern. Heute bringen Suchanfragen zum Thema Zeitgeist hauptsächlich kritische Stimmen von um ihren Datenschutz besorgten Usern zutage, die verzweifelt versuchen dem Daemon den Garaus zu machen, ohne dabei ihren Ubuntu-Desktop lahmzulegen. Auch wenn dem Projekt möglicherweise keine rosige Zukunft bevorsteht, lohnt es sich trotzdem, hinter die Kulissen zu schauen und die gesammelten Daten einer kritischen Analyse zu unterziehen.
Respektiert Privates
Weil das ungefragte Mitprotokollieren aller Aktionen auf dem Desktop die Privatsphäre des Users verletzen könnte, erlaubt es der Unity-Desktop dem User, die Sammelwut einzuschränken, ganz abzustellen oder gar alle bislang gesammelten Daten zu verwerfen. In den »System Settings« unter dem Eintrag »Security und Privacy« kann der User den Daemon durch das Deaktivieren einiger Checkboxen in seine Schranken weisen. Dann bekommt Zeitgeist eine Blacklist zugespielt und ignoriert eintrudelnde Events geblockter Applikationen.
Abbildung 2 zeigt, dass Zeitgeist sich dazu überreden lässt, wahlweise keine Aktionen betreffs Musik, Videos, Fotos, Chatlogs oder Dokumente mitzuschneiden. Mit Drücken des Buttons »Clear Data« fordert der User den Daemon sogar dazu auf, bislang gesammelte Daten permanent zu löschen. Was der Zeitgeist-Daemon so alles sammelt, zeigt auch der »zeitgeist-explorer« aus dem gleichnamigen Ubuntu-Paket grafisch an (siehe Abbildung 3).
Auf einer ganz frischen Ubuntu-Installation protokolliert Zeitgeist aber alles Erhältliche mit. Doch nicht alle Applikationen geben sich so geschwätzig wie Eye of Gnome. Wünscht sich der User etwa, dass mit Rhythmbox abgespielte Musikstücke in die Fänge des Zeitgeistes gelangen, muss er das Ubuntu-Paket »rhythmbox-plugin-zeitgeist« installieren. Für Chrome oder Firefox existieren weitere Plugins für User, die ihre Webaktivitäten mitverfolgen wollen.
Perl wühlt
Die nachfolgend vorgestellten Perl-Skripte wühlen nach Herzenslust in den gesammelten Daten herum. Um zum Beispiel festzustellen, welche neuen Fotos der User zuletzt angesehen hat, liest Listing 1 die Tabelle »uri« der SQlite-Datenbank »activity.sqlite« im Pfad ».local/share/zeitgeist« unter dem Homeverzeichnis des Users aus. Die SQL-Abfrage »SELECT * from uri« listet einfach alle Datenreihen aus der Tabelle »uri« auf, in denen Zeitgeist neu gefundenen Pfaden oder URLs Indexnummern zuweist.
Listing 1
urls-recent
01 #!/usr/local/bin/perl -w
02 use strict;
03 use DBD::SQLite;
04
05 my( $home ) = glob "~";
06 my $dbfile = "$home/.local/share/" .
07 "zeitgeist/activity.sqlite";
08 my $dbh = DBI->connect(
09 "dbi:SQLite:dbname=$dbfile", "", "" );
10
11 my $sth = $dbh->prepare(
12 "SELECT * from uri" );
13 $sth->execute();
14
15 while( my( $id, $uri ) =
16 $sth->fetchrow_array() ) {
17 print "$uri\n";
18 }
Das CPAN-Modul DBD::SQlite enthält nicht nur den Perl-Wrapper, sondern auch den C-Code des SQlite-Projekts selbst. Wer das Ubuntu-Paket »sqlite3« installiert hat, kann mit
sqlite3 activity.sqlite .schema
im Verzeichnis der Zeitgeist-Datenbank erst einmal nachsehen, welche Tabellen »in der Datenbank liegen, und später mit interaktiv abgesetzten SQL-Kommandos deren Inhalt erforschen.
Listing 1 nutzt die Methode »prepare()« des DBI-Moduls mit dem geladenen SQlite-Driver, um das SQL-Kommando vorzubereiten, und »execute()« auf das zurückkommende Statement-Handle, um es der SQlite-Engine zu übermitteln. Wie in DBI üblich, schnappen sich wiederholte Aufrufe von »fetchrow_array()« die von der Datenbank-Engine zurückkommenden Ergebnisreihen, deren jede (im Fall der Tabelle »uri« ) zwei Spaltenwerte – »id« und »value« – enthält, die das Skript zwei gleichnamigen Perl-Variablen zuweist. Abbildung 4 zeigt, dass von Listing 1 nicht nur Foto-Pfade zurückkommen, sondern auch seltsam anmutende URLs wie »application://firefox.desktop« , die von Events zeugen, bei denen der User bestimmte Applikationen, hier zum Beispiel den Firefox-Browser, aufgerufen hat.
Immer ein Ereignis
Die Datenbanktabelle »event« hingegen speichert die zeitliche Abfolge der vom Zeitgeist-Daemon aufgeschnappten Ereignisse. Die SQL-Query in Abbildung 5 zerrt einige Beispiel-Records von Events mit zugeordneten Zeitstempeln ans Licht, die mit numerischen Schlüsseln auf andere Tabellen verweisen, zum Beispiel »uri« , in denen dann der Schlüssel einem Texteintrag zugeordnet ist.
Das Zeitstempelformat der Spalte »timestamp« ist allerdings nicht ein direkt von SQlite unterstütztes, sondern die Unix-Zeit seit 1970 in Sekunden gefolgt von drei weiteren Ziffern, die Tausendstelsekunden anzeigen. Listing 2 extrahiert aus der Tabelle »event« die Desktop-Aktionen der letzten zwölf Stunden und muss das Zeitgeist-Datum im abgesetzten SQL mit
Listing 2
apps-recent
01 #!/usr/local/bin/perl -w
02 use strict;
03 use DBD::SQLite;
04
05 my( $home ) = glob "~";
06 my $dbfile = "$home/.local/share/" .
07 "zeitgeist/activity.sqlite";
08 my $dbh = DBI->connect(
09 "dbi:SQLite:dbname=$dbfile", "", "" );
10
11 my $sth = $dbh->prepare(
12 "select uri.value from event,uri where
13 subj_id = uri.id and interpretation = 1
14 AND
15 date(substr(timestamp,1,10),'unixepoch')
16 >= date('now', '-12 hours')" );
17 $sth->execute();
18
19 my %apps = ();
20
21 while( my( $uri ) =
22 $sth->fetchrow_array() ) {
23 if( $uri =~ /^application:/ ) {
24 $apps{ $uri }++;
25 }
26 }
27
28 for my $app ( sort
29 { $apps{ $b } <=> $apps{ $a } }
30 keys %apps ) {
31 print "$app: $apps{ $app }\n";
32 }
date(substr(timestamp,1,10),'unixepoch')
in ein SQlite-Datum umwandeln, bevor es den Zeitstempel mit dem im SQlite-Dialekt praktischerweise mittels »date(‘now’, ‘-12 hours’)« verfügbaren Zeitfenster vergleichen kann.
Die While-Schleife ab Zeile 21 arbeitet alle Ergeignis-Records ab und kumuliert Applikations-URLs im Hash »%apps« . Die For-Schleife ab Zeile 28 gruppiert die Einträge dann absteigend nach Zählerstand und gibt das Ergebnis aus. Abbildung 6 zeigt die Ausgabe von Listing 2, und es stellt sich heraus, dass ich in der untersuchten Zeitspanne 18-mal ein Xterm-Fenster geöffnet und insgesamt sechs Screenshots gezogen habe.
Überwacher-Stechuhr
Wie fleißig war der User in den letzten 24 Stunden? Hat er auch ordentlich auf dem Desktop herumgeklickt? Das findet Listing 3 heraus, indem es die Activity-Tabelle »event« nach Einträgen des vergangenen Tages durchforstet und pro laufender Stunde jedes Mal einen Zähler erhöht, falls ein Desktop-Ereignis in diesen Zeitrahmen fällt.
Listing 3
Last-24-hours
01 #!/usr/local/bin/perl -w
02 use strict;
03 use DBD::SQLite;
04 use DateTime::Format::SQLite;
05
06 my( $home ) = glob "~";
07 my $dbfile = "$home/.local/share/" .
08 "zeitgeist/activity.sqlite";
09 my $dbh = DBI->connect(
10 "dbi:SQLite:dbname=$dbfile", "", "" );
11
12 my $sth = $dbh->prepare(
13 "SELECT
14 datetime(substr(timestamp,1,10),
15 'unixepoch')
16 AS time FROM event WHERE
17 time >= datetime('now', '-24 hours')" );
18 $sth->execute();
19
20 my %activity = ();
21
22 while( my( $time ) =
23 $sth->fetchrow_array() ) {
24
25 my $dt = DateTime::Format::SQLite->
26 parse_datetime( $time );
27 $dt->set_time_zone( "local" );
28 $activity{ $dt->hour() }++;
29 }
30
31 my $now = DateTime->now(
32 time_zone => "local" );
33 my $dt =
34 $now->clone->subtract( days => 1 );
35
36 while( $dt < $now ) {
37 my $hour = $dt->hour();
38 printf "%02d:00 %d\n",
39 $hour, $activity{ $hour } || 0;
40 $dt = $dt->add( hours => 1 );
41 }
Datums-Tausendsassa
Der Hash »%activity« zählt in Zeile 28 jeweils um eins hoch, falls ein Ereignis in eine bestimmte Stunde fällt. Abschließend braucht die While-Schleife ab Zeile 36 nur noch vom Datum des gestrigen Tages bis heute stundenweise hochzuzählen und jeweils die Anzahl der Ereignisse mit »printf« auszudrucken.
Die Ausgabe in Abbildung 7 bestätigt, dass der User nach dem Motto “Am Abend wird der Faule fleißig” nur zwischen 19 und 23 Uhr aktiv war. Oder war es so, dass er tagsüber im Büro schuftete und sich abends und nachts an seinen Heimcomputer setzte, um Artikel fürs Linux-Magazin zu schreiben?
Online PLUS
Im Screencast demonstriert Michael Schilli das Beispiel: https://www.linux-magazin.de/Ausgaben/2015/05/plus
Infos
- Listings zu diesem Artikel: ftp://www.linux-magazin.de/pub/listings/magazin/2015/05/Perl
- Zeitgeist-Projekt auf Launchpad: https://launchpad.net/zeitgeist













