arbtt 0.4.1 → 0.4.2
raw patch · 8 files changed
+1151/−8 lines, 8 filesnew-component:exe:arbtt-recover
Files
- arbtt.cabal +13/−2
- doc/Makefile +33/−0
- doc/arbtt.xml +948/−0
- doc/fptools.css +39/−0
- src/Data.hs +1/−1
- src/TimeLog.hs +38/−0
- src/dump-main.hs +12/−5
- src/recover-main.hs +67/−0
arbtt.cabal view
@@ -1,5 +1,5 @@ name: arbtt-version: 0.4.1+version: 0.4.2 license: GPL license-file: LICENSE category: Desktop@@ -22,7 +22,8 @@ extra-source-files:- categorize.cfg, arbtt-capture.desktop, README+ categorize.cfg, arbtt-capture.desktop, README,+ doc/arbtt.xml, doc/fptools.css, doc/Makefile executable arbtt-capture main-is: capture-main.hs@@ -53,6 +54,16 @@ executable arbtt-dump main-is: dump-main.hs+ hs-source-dirs: src+ build-depends:+ base == 4.*, parsec == 2.*, containers+ other-modules:+ Data+ TimeLog+ System.Locale.SetLocale++executable arbtt-recover+ main-is: recover-main.hs hs-source-dirs: src build-depends: base == 4.*, parsec == 2.*, containers
+ doc/Makefile view
@@ -0,0 +1,33 @@+all: html man++XSLTPROC=xsltproc+XSLTPROC_HTML_OUTDIR=users_guide/+XSLTPROC_HTML_CSS=fptools.css+XSLTPROC_HTML_PARAMS=\+ --stringparam use.id.as.filename 1 \+ --stringparam base.dir $(XSLTPROC_HTML_OUTDIR) \+ --stringparam html.stylesheet $(XSLTPROC_HTML_CSS)+XSLTPROC_HTML_STYLESHEET=/usr/share/xml/docbook/stylesheet/nwalsh/xhtml/profile-chunk.xsl+XSLTPROC_MAN_STYLESHEET=/usr/share/xml/docbook/stylesheet/nwalsh/manpages/profile-docbook.xsl+XSLTPROC_MAN_OUTDIR=man/+XSLTPROC_MAN_OPTIONS=--stringparam man.output.in.separate.dir 1 --stringparam man.output.base.dir++# build targets+#+.PHONY: man html pdf+man: + $(XSLTPROC) --xinclude --stringparam profile.condition man $(XSLTPROC_MAN_OPTIONS) $(XSLTPROC_MAN_OUTDIR) $(XSLTPROC_MAN_STYLESHEET) arbtt.xml++html:+ $(XSLTPROC) --xinclude --stringparam profile.condition html $(XSLTPROC_HTML_PARAMS) $(XSLTPROC_HTML_STYLESHEET) arbtt.xml+ cp $(XSLTPROC_HTML_CSS) $(XSLTPROC_HTML_OUTDIR)++pdf:+ #dblatex -tpdf arbtt.xml+ fop -xml arbtt.xml -xsl /usr/share/xml/docbook/stylesheet/docbook-xsl/fo/docbook.xsl -pdf arbtt.pdf++# auxiliary targets+#+.PHONY: clean+clean:+ -rm -rf users_guide/ man/ arbtt.pdf
+ doc/arbtt.xml view
@@ -0,0 +1,948 @@+<?xml version="1.0" encoding="utf-8"?>+<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook EBNF Module V1.1CR1//EN"+ "http://www.oasis-open.org/docbook/xml/ebnf/1.1CR1/dbebnf.dtd">+<!--+<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"+ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" []>+-->+<article>+<articleinfo>+ <title>arbtt – The Automatic Rule-Base Time Tracker</title>+ <authorgroup>+ <author>+ <firstname>Joachim</firstname>+ <surname>Breitner</surname>+ <email>mail@joachim-breitner.de</email>+ <contrib>Main author of arbtt</contrib>+ </author>+ </authorgroup>+ <pubdate>October 2009</pubdate>+</articleinfo>+<abstract>+ <para>+ arbtt is a background daemon that stores which windows are open, which one+ has the focus and how long since your last action (and possibly more sources+ later), and stores this. It is also a program that will, based on+ expressive rules you specify, derive what you were doing, and what for.+ </para>++ <warning><para>The log file might contain very sensitive private data. Make sure+ you understand the consequences of a full-time logger and be careful with this+ data.</para></warning>+</abstract>++<sect1 id="installation">+ <title>Installation</title>+ <sect2>+ <title>Building with <command>cabal-install</command></title>+ <para>+ arbtt comes in the form of a Cabalized<footnote><para>Cabal is the common software+ packaging for Haskell programs and libraries, see <ulink+ url="http://www.haskell.org/cabal/"/>.</para></footnote> package, and is+ available from hackage. The easiest way of obtaining and installing arbtt is+ via <command>cabal-install</command>. If you have+ <command>cabal-install</command> available, just run+ <screen>$ cabal install arbtt</screen>+ to download, build and install arbtt.+ </para>+ </sect2>++ <sect2>+ <title>Building without <command>cabal-install</command></title>+ <para>+ You can fetch the latest arbtt source tarball from hackage, at+ <ulink url="http://hackage.haskell.org/package/arbtt"/>. Extract the tarball+ and run the following commands to build and install the arbtt binaries:+ <screen>$ runhaskell Setup.hs configure+$ runhaskell Setup.hs build+$ runhaskell Setup.hs install</screen>+ </para>+ </sect2>++ <sect2>+ <title>Setting up the capture program</title>+ <para>+ To have arbtt gather useful data, you need to make sure that+ <command>arbtt-capture</command> is started with your X session. If you use+ GNOME or KDE, you can copy the file+ <filename>arbtt-capture.desktop</filename> to+ <filename>~/.config/autostart/</filename>. You might need to put the full+ path to <command>arbtt-capture</command> in the Exec line there, if you did+ not do a system wide installation.+ </para>+ <para>+ By default, <command>arbtt-capture</command> will save one data sample per+ minute. If you want to change that, you can pass <option>--sample-rate+ <replaceable>RATE</replaceable></option> to <command>arbtt-capture</command>, where+ <replaceable>RATE</replaceable> specifies the sample rate in seconds.+ </para>+ </sect2>++ <sect2>+ <title>Building the documentation</title>+ <para>+ Obviously, you can already read the documentation. If you still want to+ build it yourself, enter the directory <filename>doc/</filename> and run+ <command>make</command> for the documentation in HTML and PDF format. + </para>+ </sect2>+++ <sect2>+ <title>Development version</title>+ <para>+ If you want to try the latest unreleased state of the code, or want to+ contribute to arbtt, you can fetch the code with+ <screen>darcs get <ulink url="http://darcs.nomeata.de/arbtt"/></screen>+ </para>+ </sect2>++</sect1>++<sect1 id="configuration">+ <title>Configuring the arbtt categorizer</title>+ <para>+ Once arbtt-capture is running, it will start recording, without further+ configuration. The configuration is only needed to do an analysis of the+ recorded data. Thus, if you improve your categorization later, it will apply+ even to previous data samples!+ </para>++ <para>+ The configuration file needs to be placed in+ <filename>~/.arbtt/categorize.cfg</filename>. An+ example file is included in the source distribution, and reproduced here as+ <xref linkend="catex"/>, which should be more enlightening than this rather+ formal description.+ </para>++ <example id="catex">+ <title>A complete <filename>categorize.cfg</filename></title>+ <programlisting><xi:include href="../categorize.cfg" parse="text" + xmlns:xi="http://www.w3.org/2001/XInclude" /></programlisting>+ </example>++ <sect2>+ <title>The syntax</title>+ <para>+ The file <filename>categorize.cfg</filename> is a plain text file.+ Whitespace is insignificant and Haskell-style comments are allowed. A formal+ grammar is provided in <xref linkend="grammar"/>.+ </para>++ <figure id="grammar">+ <title>The formal grammar of <filename>categorize.cfg</filename></title>+ <productionset>+ <production id="g-rules">+ <lhs>Rules</lhs>+ <rhs>+ [ <nonterminal def="#g-aliasspec"/> ]+ <nonterminal def="#g-rule"/> ( (<quote>,</quote>+ <nonterminal def="#g-rule"/>)* | ( <quote>;</quote>+ <nonterminal def="#g-rule"/>)* )+ </rhs>+ </production>++ <production id="g-aliasspec">+ <lhs>AliasSpec</lhs>+ <rhs><quote>aliases</quote> <quote>(</quote> <nonterminal+ def="#g-alias"/> (<quote>,</quote> <nonterminal def="#g-alias"/>)*+ <quote>)</quote> </rhs>+ </production>++ <production id="g-alias">+ <lhs>Alias</lhs>+ <rhs>Literal <quote>-></quote> Literal</rhs>+ </production>++ <production id="g-rule">+ <lhs>Rule</lhs>+ <rhs><quote>{</quote> <nonterminal def="#g-rules"/>+ <quote>}</quote>+ </rhs>+ <rhs>+ <nonterminal def="#g-cond"/> <quote>==></quote> + <nonterminal def="#g-rule"/> | <quote>if</quote>+ <nonterminal def="#g-cond"/> <quote>then</quote>+ <nonterminal def="#g-rule"/> <quote>else</quote>+ <nonterminal def="#g-rule"/>+ </rhs>+ <rhs>+ <quote>tag</quote> <nonterminal def="#g-tag"/>+ </rhs>+ </production>++ <production id="g-cond">+ <lhs>Cond</lhs>+ <rhs><quote>(</quote> <nonterminal def="#g-cond"/>+ <quote>)</quote>+ </rhs>+ <rhs><quote>!</quote> <nonterminal def="#g-cond"/> |+ <nonterminal def="#g-cond"/> <quote>&&</quote>+ <nonterminal def="#g-cond"/> |+ <nonterminal def="#g-cond"/> <quote>||</quote> <nonterminal+ def="#g-cond"/>+ </rhs>+ <rhs> <quote>$</quote> <nonterminal def="#g-svar"/>+ <quote>==</quote> String |+ <quote>$</quote> <nonterminal def="#g-svar"/>+ <quote>/=</quote> String+ </rhs>+ <rhs> <quote>$</quote> <nonterminal def="#g-svar"/>+ <quote>=~</quote> <nonterminal def="#g-regex"/></rhs>+ <rhs> <quote>$</quote> <nonterminal def="#g-nvar"/>+ <nonterminal def="#g-cmpop"/> Number+ </rhs>+ <rhs> <quote>$</quote> <nonterminal def="#g-tvar"/>+ <nonterminal def="#g-cmpop"/> <nonterminal def="#g-tspec"/>+ </rhs>+ <rhs> <quote>$</quote> <nonterminal def="#g-bvar"/>+ </rhs>+ <rhs> <quote>current window</quote> <nonterminal def="#g-cond"/> </rhs>+ <rhs> <quote>any window</quote> <nonterminal def="#g-cond"/> </rhs>+ </production>++ <production id="g-tag">+ <lhs>Tag</lhs>+ <rhs> [ Literal <quote>:</quote> ] Literal </rhs>+ </production>++ <production id="g-regex">+ <lhs>RegEx</lhs>+ <rhs> <quote>/</quote> Literal <quote>/</quote> |+ <quote>m</quote> <replaceable>c</replaceable> Literal+ <replaceable>c</replaceable><lineannotation>Where+ <replaceable>c</replaceable> can be any+ character.</lineannotation> </rhs>+ </production>++ <production id="g-cmpop">+ <lhs>CmpOp</lhs>+ <rhs><quote><=</quote> | <quote><</quote> | <quote>==</quote>+ | <quote>></quote> | <quote>>=</quote></rhs>+ </production>++ <production id="g-svar">+ <lhs>StringVariable</lhs>+ <rhs><quote>title</quote> | <quote>program</quote></rhs>+ </production>++ <production id="g-nvar">+ <lhs>NumericVariable</lhs>+ <rhs><quote>idle</quote></rhs>+ </production>++ <production id="g-bvar">+ <lhs>BooleanVariable</lhs>+ <rhs><quote>active</quote></rhs>+ </production>++ <production id="g-tvar">+ <lhs>TimeVariable</lhs>+ <rhs><quote>time</quote> | <quote>sampleage</quote></rhs>+ </production>++ <production id="g-tspec">+ <lhs>TimeSpecification</lhs>+ <rhs>[ Digit ] Digit <quote>:</quote> Digit Digit</rhs>+ </production>++ </productionset>+ </figure>+ <para>+ A <literal>String</literal> refers to a double-quoted string of+ characters, while a <literal>Literal</literal> is not quoted.+ <nonterminal def="#g-tag">Tags</nonterminal> may only consist of+ letters, dashes and underscores, or variable interpolations. A Tag maybe+ be optionally prepended with a category, separated by a colon. The+ category itself follows he same lexical rules as the tag. A variable+ interpolation can be one of the following:+ <variablelist>+ <varlistentry>+ <term><literal>$1</literal>, <literal>$2</literal>,...</term>+ <listitem><simpara> will be replaced by the respective group in the last+ successfully applied regular expression in the conditions enclosing the+ current rule.+ </simpara></listitem>+ </varlistentry>+ <varlistentry>+ <term><literal>$current.title</literal></term>+ <term><literal>$current.program</literal></term>+ <listitem><simpara> will be replaced by title the currently active+ window, resp. by the name of the currently active program.+ If no window happens to be active, this tag will be ignored.+ </simpara></listitem>+ </varlistentry>+ </variablelist>+ </para>++ <para>+ A regular expression is, like in perl, either enclosed in forward+ slashes or, alternatively, in any character of your choice with an+ <literal>m</literal> (for <quote>match</quote>) in front. This is handy if you need+ to use regular expressions that match directory names. Otherwise, the+ syntax of the regular expressions is that of perl-compatible regular+ expressions.+ </para>+ </sect2>+ <sect2>+ <title>The semantics</title>+ <para>+ A data sample consists of the time of recording, the time passed since the+ user’s last action and the list of windows. Per window, the following+ information is available:+ <itemizedlist>+ <listitem><simpara>the window title</simpara></listitem>+ <listitem><simpara>the program name</simpara></listitem>+ <listitem><simpara>whether the window was the active window</simpara></listitem>+ </itemizedlist>+ Base on this information, the categorizer will now assign+ <emphasis>tags</emphasis> to each+ sample, based on the rules layed out in+ <filename>categorizer.cfg</filename>.+ </para>++ <para>+ The keyword <literal>tag</literal>, usually wrapped in a condition,+ assigns the tag to the sample. If the tag also contains a+ <emphasis>category</emphasis>, it will only be assigned if no other tag of that+ category is present. This means that for each sample and each category,+ there can only be one tag of that category. Tags can contain references to+ matches done of regular expressions in conditions.+ </para>++ <para>+ The variable <literal>$idle</literal> contains the idle time of the user,+ measured in seconds. Usually, it is used to assign the tag+ <literal>inactive</literal>, which is handled specially by+ <command>arbtt-stats</command>, as can be seen in <xref linkend="catex"/>.+ </para>++ <para>+ While applying the conditions and rules, the categorizer has a notion of+ the <emphasis>window in scope</emphasis>, and the variables+ <literal>$title</literal>, <literal>$program</literal> and+ <literal>$active</literal> always refer to the window in scope. At first,+ no window is in scope. Only when evaluating a condition wrapped in+ <literal>current window</literal> or <literal>any window</literal>, this+ changes.+ </para>++ <para>+ For <literal>current window</literal>, the currently active window is in+ scope. If there is no such window, the condition is false.+ </para>+ + <para>+ For <literal>any window</literal>, the condition is applied to each+ window, in turn, and if any of the windows matches, the result is true. If+ more than one window matches it is not defined from which match the+ variables <literal>$1</literal>... are take from.+ </para>++ <para>+ The variable <literal>$time</literal> refers to the time-of-day of the+ sample (i.e. the time since 0:00 that day), while+ <literal>$sampleage</literal> refers to the+ time span from when the sample was created until now, the time of+ evaluating the statistics. The latter variable is especially useful when+ passed to the <option>--filter</option> option of+ <command>arbtt-stats</command>.+ They can be compared with expressions of the+ type "hh:mm", for example+ <programlisting>$time >= 8:00 && $time < 12:00 ==> tag time-of-day:morning</programlisting>+ </para>+ </sect2>+</sect1>++<sect1 id="references">+ <title>Program references</title>+ <para>arbtt consists of a few command line tools, the most important one is+ <command>arbtt-stats</command>. This overview is followed by their manual+ pages.+ </para>+ + <!-- <sect2>+ <title>Generating statistics</title> -->+ <para>To generate statistics about the data that+ <command>arbtt-capture</command> has gathered, use the program+ <command>arbtt-stats</command>. A detailed description of the possible+ options is given in <xref linkend="arbtt-stats"/>.</para>+ <!--+ </sect2>++ <sect2>+ <title>Gathering data</title>+ -->+ <para>The collection of data is done by <command>arbtt-capture</command>.+ Usually, you only set it up once to run automatically, as described in <xref+ linkend="installation"/>, and do not have to+ worry about it again. Its command line reference is given in <xref+ linkend="arbtt-capture"/>.</para>+ <!--+ </sect2>++ <sect2>+ <title>Dumping data</title>+ -->+ <para>Because the data log file is binary, a tool names+ <command>arbtt-dump</command> can bee used to dump the data in+ textual form. Its command line reference is given in <xref+ linkend="arbtt-dump"/>.</para>++ <para>If <command>arbtt-capture</command> crashes it might be that the log+ file is not readable any more. In some cases, this can be fixed using the+ (relatively raw) <command>arbtt-recover</command> tool. Its command line+ reference is given in <xref linkend="arbtt-recover"/>.</para>+ <!--+ </sect2>+ -->+++ <refentry id="arbtt-stats">+ <refmeta>+ <refentrytitle>arbtt-stats</refentrytitle>+ <manvolnum>1</manvolnum>+ <refmiscinfo class="source">arbtt manual</refmiscinfo>+ </refmeta>++ <refnamediv>+ <refname>arbtt-stats</refname>+ <refpurpose>generate statistics from the arbtt data samples</refpurpose>+ </refnamediv>+ + <refsynopsisdiv>+ <cmdsynopsis>+ <command>arbtt-stats</command>+ <arg rep="repeat">OPTION</arg>+ </cmdsynopsis>+ </refsynopsisdiv>++ <refsect1><title>Description</title>+ <para>+ <command>arbtt-stats</command> reads the samples that were recorded so far+ by <command>arbtt-capture</command> from the log file, filters them+ according to the users specifications and generates one or more reports+ from the data.+ </para>+ <para>+ When run without any options, <option>--total-time</option> is assumed.+ </para>+ <para>+ The order in which filters (<option>--exclude</option>,+ <option>--only</option>, <option>--also-inactive</option> and+ <option>--filter</option>) and reports are passed to the program is+ irrelevant: All filters given on the command line are active for all+ reports.+ </para>+ </refsect1>++ <refsect1><title>Options</title>+ <variablelist>+ <varlistentry>+ <term><option>-h</option></term>+ <term><option>-?</option></term>+ <term><option>--help</option></term>+ <listitem><simpara>shows a short summary of the available+ options, and exists.</simpara></listitem>+ </varlistentry>+ <varlistentry>+ <term><option>-V</option></term>+ <term><option>--version</option></term>+ <listitem><simpara>shows the version number, and exists.</simpara></listitem>+ </varlistentry>+ </variablelist>+ <refsect2><title>Filtering options</title>+ <variablelist>+ <varlistentry>+ <term><option>-x</option> <replaceable>TAG</replaceable></term>+ <term><option>--exclude</option> <replaceable>TAG</replaceable></term>+ <listitem><simpara>Ignore any data samples that have+ been assigned this tag. Can be given more than once.</simpara></listitem>+ </varlistentry>+ <varlistentry>+ <term><option>-o</option> <replaceable>TAG</replaceable></term>+ <term><option>--only</option> <replaceable>TAB</replaceable></term>+ <listitem><simpara>Ignore any data samples that have+ not been assigned this tag. Can be given more than once.</simpara></listitem>+ </varlistentry>+ <varlistentry>+ <term><option>--also-inactive</option></term>+ <listitem><simpara>by default, <command>arbtt-stats</command> ignores+ any samples which have been assigned the tag+ <literal>inactive</literal>. This flag disables this behaviour.</simpara></listitem>+ </varlistentry>+ <varlistentry>+ <term><option>-f</option> <replaceable>CONDITION</replaceable></term>+ <term><option>--filter</option> <replaceable>CONDITION</replaceable></term>+ <listitem><simpara>Only consider samples matching+ the given condition, which follows the same syntax as in+ <filename>categorize.cfg</filename> (Nonterminal <nonterminal def="#g-cond"/> in+ <phrase condition="html"><xref linkend="grammar"/></phrase><phrase condition="man">the formal grammar specification found in the user guide</phrase>).</simpara></listitem>+ </varlistentry>+ </variablelist>+ </refsect2>+ <refsect2><title>Report options</title>+ <variablelist>+ <varlistentry>+ <term><option>-m</option> <replaceable>PERCENTAGE</replaceable></term>+ <term><option>--min-percentage</option> <replaceable>PERCENTAGE</replaceable></term>+ <listitem><para>+ In the reports, any tag which occurs rarer than the given+ percentage is ignored. The default value is 1.+ </para></listitem>+ </varlistentry>+ </variablelist>+ </refsect2>+ <refsect2><title>Reports</title>+ <variablelist>+ <varlistentry>+ <term><option>-i</option></term>+ <term><option>--information</option></term>+ <listitem><para>+ Various bits of information about the recorded data, such as total+ time recorded, number of records etc. In this report, <quote>time+ recorded</quote> is the sum of <emphasis>all</emphasis>+ samples, including inactive and those that are disabled by the+ filter, while <quote>time selected</quote> is the sum of the+ samples that are matched by the given filters.+ </para></listitem>+ </varlistentry>+ <varlistentry>+ <term><option>-t</option></term>+ <term><option>--total-time</option></term>+ <listitem><para>For all tag, print the part of the selected time+ with this tag applied to, both as an absolute value and a percentage+ of the selected time.+ </para></listitem>+ </varlistentry>+ <varlistentry>+ <term><option>-c</option> <replaceable>CATEGORY</replaceable></term>+ <term><option>--category</option> <replaceable>CATEGORY</replaceable></term>+ <listitem><para>For the given category, give the textual equivalent+ of a pie chart: For each possible value of the category, including+ one for <quote>no tag of this category present</quote>, give the absolute time and+ fraction. Entries which are not displayed because of the option+ <option>--min-percentage</option> are aggregated.</para></listitem>+ </varlistentry>+ <varlistentry>+ <term><option>--each-category</option></term>+ <listitem><para>This is just a shortcut for a series of+ <option>--category</option> options, one for each category found in+ the data.+ </para></listitem>+ </varlistentry>+ </variablelist>+ </refsect2>+ </refsect1>++ <refsect1><title>Examples</title>+ <para>Some useful examples of what you can do with+ <command>arbtt-stats</command> are provided here:</para>+ <screen># Only consider the time when I was programming in Haskell +arbtt-stats -o Editing-Haskell++# Tell me what evolution folders I spend my time in when I actually do+# work with e-Mail+arbtt-stats -o Program:evolution -c Evo-Folder++# Generate statistics about the last hour+arbtt-stats -f '$sampleage < 1:00'</screen>+ </refsect1>++ <refsect1><title>Files</title>+ <variablelist>+ <varlistentry>+ <term><filename>~/.arbtt/capture.log</filename></term>+ <listitem><para>binary file, storing the arbtt data samples</para></listitem>+ </varlistentry>+ <varlistentry>+ <term><filename>~/.arbtt/categorize.cfg</filename></term>+ <listitem><para>specification of the arbtt categorizer syntax. A+ detailed description is given in <xref linkend="configuration"/></para></listitem>+ </varlistentry>+ </variablelist>+ </refsect1>++ <refsect1><title>See also</title>+ <para>See the arbtt manual for more information and the <ulink+ url="http://www.hackage.org/package/arbtt">arbtt hackage page</ulink> for+ newer versions of arbtt.</para>+ </refsect1>+ </refentry>+ + <refentry id="arbtt-capture">+ <refmeta>+ <refentrytitle>arbtt-capture</refentrytitle>+ <manvolnum>1</manvolnum>+ <refmiscinfo class="source">arbtt manual</refmiscinfo>+ </refmeta>++ <refnamediv>+ <refname>arbtt-capture</refname>+ <refpurpose>collect data samples for arbtt</refpurpose>+ </refnamediv>+ + <refsynopsisdiv>+ <cmdsynopsis>+ <command>arbtt-capture</command>+ <arg rep="repeat">OPTION</arg>+ </cmdsynopsis>+ </refsynopsisdiv>++ <refsect1><title>Description</title>+ <para>+ <command>arbtt-capture</command> runs continuously and saves at the given+ sample rate, usually once per minute, the collected data to+ <filename>~/.arbtt/capture.log</filename>. + </para>+ </refsect1>++ <refsect1><title>Options</title>+ <variablelist>+ <varlistentry>+ <term><option>-h</option></term>+ <term><option>-?</option></term>+ <term><option>--help</option></term>+ <listitem><simpara>shows a short summary of the available+ options, and exists.</simpara></listitem>+ </varlistentry>+ <varlistentry>+ <term><option>-V</option></term>+ <term><option>--version</option></term>+ <listitem><simpara>shows the version number, and exists.</simpara></listitem>+ </varlistentry>+ <varlistentry>+ <term><option>-r</option> <replaceable>RATE</replaceable></term>+ <term><option>--rate</option> <replaceable>RATE</replaceable></term>+ <listitem><simpara>set the sample rate in seconds (default: 60)</simpara></listitem>+ </varlistentry>+ </variablelist>+ </refsect1>+ <refsect1><title>Files</title>+ <variablelist>+ <varlistentry>+ <term><filename>~/.arbtt/capture.log</filename></term>+ <listitem><para>binary file, storing the arbtt data samples</para></listitem>+ </varlistentry>+ </variablelist>+ </refsect1>+++ <refsect1><title>See also</title>+ <para>See the arbtt manual for more information and the <ulink+ url="http://www.hackage.org/package/arbtt">arbtt hackage page</ulink> for+ newer versions of arbtt.</para>+ </refsect1>+ </refentry>++ <refentry id="arbtt-dump">+ <refmeta>+ <refentrytitle>arbtt-dump</refentrytitle>+ <manvolnum>1</manvolnum>+ <refmiscinfo class="source">arbtt manual</refmiscinfo>+ </refmeta>++ <refnamediv>+ <refname>arbtt-dump</refname>+ <refpurpose>dumps arbtt data samples</refpurpose>+ </refnamediv>+ + <refsynopsisdiv>+ <cmdsynopsis>+ <command>arbtt-dump</command>+ <arg rep="repeat">OPTION</arg>+ </cmdsynopsis>+ </refsynopsisdiv>++ <refsect1><title>Description</title>+ <para>+ <command>arbtt-dump</command> reads the data samples recorded by <xref+ linkend="arbtt-capture"/> and writes them so the standard output in an+ ascii based format.+ </para>+ </refsect1>++ <refsect1><title>Options</title>+ <variablelist>+ <varlistentry>+ <term><option>-h</option></term>+ <term><option>-?</option></term>+ <term><option>--help</option></term>+ <listitem><simpara>shows a short summary of the available+ options, and exists.</simpara></listitem>+ </varlistentry>+ <varlistentry>+ <term><option>-V</option></term>+ <term><option>--version</option></term>+ <listitem><simpara>shows the version number, and exists.</simpara></listitem>+ </varlistentry>+ <varlistentry>+ <term><option>-f</option></term>+ <term><option>--logfile</option></term>+ <listitem><simpara>logfile to use instead of <filename>~/.arbtt/capture.log</filename></simpara></listitem>+ </varlistentry>+ </variablelist>+ </refsect1>+ <refsect1><title>Files</title>+ <variablelist>+ <varlistentry>+ <term><filename>~/.arbtt/capture.log</filename></term>+ <listitem><para>binary file, storing the arbtt data samples</para></listitem>+ </varlistentry>+ </variablelist>+ </refsect1>++ <refsect1><title>See also</title>+ <para>See the arbtt manual for more information and the <ulink+ url="http://www.hackage.org/package/arbtt">arbtt hackage page</ulink> for+ newer versions of arbtt.</para>+ </refsect1>+ </refentry>++ <refentry id="arbtt-recover">+ <refmeta>+ <refentrytitle>arbtt-recover</refentrytitle>+ <manvolnum>1</manvolnum>+ <refmiscinfo class="source">arbtt manual</refmiscinfo>+ </refmeta>++ <refnamediv>+ <refname>arbtt-recover</refname>+ <refpurpose>tries to recover a broken arbtt data log</refpurpose>+ </refnamediv>+ + <refsynopsisdiv>+ <cmdsynopsis>+ <command>arbtt-recover</command>+ <arg rep="repeat">OPTION</arg>+ </cmdsynopsis>+ </refsynopsisdiv>++ <refsect1><title>Description</title>+ <para>+ <command>arbtt-recover</command> tries to readsthe data samples recorded+ by <xref linkend="arbtt-capture"/>, skipping over possible broken entries. A fixed log file is written to <file>~/.arbtt/capture.log.recovered</file>.+ </para>+ </refsect1>++ <refsect1><title>Options</title>+ <variablelist>+ <varlistentry>+ <term><option>-h</option></term>+ <term><option>-?</option></term>+ <term><option>--help</option></term>+ <listitem><simpara>shows a short summary of the available+ options, and exists.</simpara></listitem>+ </varlistentry>+ <varlistentry>+ <term><option>-V</option></term>+ <term><option>--version</option></term>+ <listitem><simpara>shows the version number, and exists.</simpara></listitem>+ </varlistentry>+ <varlistentry>+ <term><option>-i</option></term>+ <term><option>--infile</option></term>+ <listitem><simpara>logfile to use instead of <filename>~/.arbtt/capture.log</filename></simpara></listitem>+ </varlistentry>+ <varlistentry>+ <term><option>-o</option></term>+ <term><option>--outfile</option></term>+ <listitem><simpara>where to save the recovered file, instead of <filename>~/.arbtt/capture.log</filename></simpara></listitem>+ </varlistentry>+ </variablelist>+ </refsect1>+ <refsect1><title>Files</title>+ <variablelist>+ <varlistentry>+ <term><filename>~/.arbtt/capture.log</filename></term>+ <listitem><para>binary file, storing the arbtt data samples</para></listitem>+ </varlistentry>+ <varlistentry>+ <term><filename>~/.arbtt/capture.log.recovered</filename></term>+ <listitem><para>binary file, storing the fixed arbtt data samples</para></listitem>+ </varlistentry>+ </variablelist>+ </refsect1>++ <refsect1><title>See also</title>+ <para>See the arbtt manual for more information and the <ulink+ url="http://www.hackage.org/package/arbtt">arbtt hackage page</ulink> for+ newer versions of arbtt.</para>+ </refsect1>+ </refentry>+</sect1>++<sect1 id="copyright">+ <title>Copyright and Contact</title>+ <para>+ arbtt is Copyright © 2009 Joachim Breitner+ </para>++ <para>+ arbtt does not have a bug tracker or other project infrastructure yet. If+ you have bug reports, suggestions or questions, please send an email to+ <ulink+ url="mailto:mail@joachim-breitner.de">mail@joachim-breitner.de</ulink>.+ </para>++ <sect2>+ <title>arbtt License</title>+ <para>+ <literallayout>+This program is free software; you can redistribute it and/or modify+it under the terms of the GNU General Public License as published by+the Free Software Foundation; either version 2 of the License, or+(at your option) any later version.++This program is distributed in the hope that it will be useful,+but WITHOUT ANY WARRANTY; without even the implied warranty of+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the+GNU General Public License for more details.++You should have received a copy of the GNU General Public License+along with this program; if not, write to the Free Software+Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.+ </literallayout>+ </para>+ </sect2>+</sect1>++<sect1 id="release-notes">+ <title>Release Notes</title>+ <para>+ The version history with changes relevant for the user are documented here.+ </para>++ <sect2>+ <title>Version 0.4.2</title>+ <itemizedlist>+ <listitem>+ <para>Implement option <option>--logfile</option> to+ <command>arbtt-dump</command>.</para>+ </listitem>+ <listitem>+ <para>New command <command>arbtt-recover</command> to rescue data from+ a proken data log file.</para>+ </listitem>+ <listitem>+ <para>Actually include this documentation in the released tarball.</para>+ </listitem>+ </itemizedlist>+ </sect2>++ <sect2>+ <title>Version 0.4.1</title>+ <itemizedlist>+ <listitem>+ <para>Write this documentation</para>+ </listitem>+ <listitem>+ <para>Drop dependency on setlocale: Copy the SetLocale module.</para>+ </listitem>+ <listitem>+ <para>Drop dependency on tabular: Implement custom table rendering code.</para>+ </listitem>+ <listitem>+ <para>In the absence of _NET_CLIENT_LIST, look for application windows as children of the root windows. This should work for users of window managers like i3 without EWHM support.</para>+ </listitem>+ </itemizedlist>+ </sect2>++ <sect2>+ <title>Version 0.4</title>+ <itemizedlist>+ <listitem>+ <para>Implement option <option>--each-categories</option> to+ <command>arbtt-stats</command></para>+ </listitem>+ <listitem>+ <para>Eliminate one possible cause for crashes of+ <command>arbtt-capture</command>.</para>+ </listitem>+ </itemizedlist>+ </sect2>++ <sect2>+ <title>Version 0.3.0</title>+ <itemizedlist>+ <listitem>+ <para>Switch to binary log file format, for greatly increased speed</para>+ </listitem>+ <listitem>+ <para><command>arbtt-capture</command> will automatically detect and+ convert log files in the old format.</para>+ </listitem>+ </itemizedlist>+ </sect2>++ <sect2>+ <title>Version 0.2.0</title>+ <itemizedlist>+ <listitem>+ <para>Add option <option>--filter</option> to+ <command>arbtt-stats</command></para>+ </listitem>+ <listitem>+ <para>Add option <option>--sample-rate</option> to+ <command>arbtt-capture</command></para>+ </listitem>+ <listitem>+ <para>Introduce time-base variables <literal>$time</literal> and+ <literal>$sampleage</literal></para>+ </listitem>+ </itemizedlist>+ </sect2>++ <sect2>+ <title>Version 0.1.5</title>+ <itemizedlist>+ <listitem>+ <para>Use <function>setlocale</function> to get umlauts in window titles correctly</para>+ </listitem>+ </itemizedlist>+ </sect2>++ <sect2>+ <title>Version 0.1.4</title>+ <itemizedlist>+ <listitem>+ <para>Be smarter when figuring out what window is active. Thanks to CJ+ van den Berg for investigating the issue.</para>+ </listitem>+ </itemizedlist>+ </sect2>++ <sect2>+ <title>Version 0.1.3</title>+ <itemizedlist>+ <listitem><para>Read <literal>_NET_CLIENT_LIST</literal> for the list of+ applications, for compatibility with window managers such as metacity</para></listitem>+ </itemizedlist>+ </sect2>++ <sect2>+ <title>Version 0.1.2</title>+ <itemizedlist>+ <listitem><para>Off-By-Ten error in the time display</para></listitem>+ <listitem><para>Correctly show total number of records in+ <option>--information</option></para></listitem>+ </itemizedlist>+ </sect2>++ <sect2>+ <title>Version 0.1.1</title>+ <para>+ Rename files to allow building on MacOS.+ </para>+ </sect2>++ <sect2>+ <title>Version 0.1</title>+ <para>+ Initial release of arbtt+ </para>+ </sect2>+</sect1>++</article>
+ doc/fptools.css view
@@ -0,0 +1,39 @@+div {+ font-family: sans-serif;+ color: black;+ background: white+}++h1, h2, h3, h4, h5, h6, p.title { color: #005A9C }++h1 { font: 170% sans-serif }+h2 { font: 140% sans-serif }+h3 { font: 120% sans-serif }+h4 { font: bold 100% sans-serif }+h5 { font: italic 100% sans-serif }+h6 { font: small-caps 100% sans-serif }++pre {+ font-family: monospace;+ border-width: 1px;+ border-style: solid;+ padding: 0.3em+}++pre.screen { color: #006400 }+pre.programlisting { color: maroon }++div.example {+ margin: 1ex 0em;+ border: solid #412e25 1px;+ padding: 0ex 0.4em+}++div.example, div.example-contents {+ background-color: #fffcf5+}++a:link { color: #0000C8 }+a:hover { background: #FFFFA8 }+a:active { color: #D00000 }+a:visited { color: #680098 }
src/Data.hs view
@@ -89,5 +89,5 @@ put (cLastActivity cd) get = do v <- getWord8- when (v /= 1) $ error $ "Wrong TimeLogEntry version tag " ++ show v+ when (v /= 1) $ error $ "Wrong CaptureData version tag " ++ show v CaptureData <$> get <*> get
src/TimeLog.hs view
@@ -12,8 +12,11 @@ import Data.Function import Data.Char import System.Directory+import Control.Exception+import Prelude hiding (catch) import qualified Data.ByteString.Lazy as BS+import Data.Maybe magic = BS.pack $ map (fromIntegral.ord) "arbtt-timelog-v1\n" @@ -38,6 +41,41 @@ writeTimeLog :: Binary a => FilePath -> TimeLog a -> IO () writeTimeLog filename tl = do createTimeLog True filename mapM_ (appendTimeLog filename) tl++-- | This might be very bad style, and it hogs memory, but it might help in some situations...+recoverTimeLog :: Binary a => FilePath -> IO (TimeLog a)+recoverTimeLog filename = do+ content <- BS.readFile filename+ start content+ where start content = do+ let (startString, rest, off) = runGetState (getLazyByteString (BS.length magic)) content 0+ if startString /= magic+ then do putStrLn $ "WARNING: Timelog starts with unknown marker " +++ show (map (chr.fromIntegral) (BS.unpack startString))+ else do putStrLn $ "Found header, continuing... (" ++ show (BS.length rest) ++ " bytes to go)"+ go rest off+ go input off = do mb <- tryGet False input off+ flip (maybe (return [])) mb $+ \(v,rest,off') -> if BS.null rest+ then return [v]+ else (v :) <$> go rest off'+ tryGet retrying input off = catch (+ do -- putStrLn $ "Trying value at offset " ++ show off+ let (v,rest,off') = runGetState get input off+ evaluate rest+ when retrying $+ putStrLn $ "Succesfully read value at position " ++ show off+ return (Just (v,rest,off'))+ ) (+ \e -> do+ putStrLn $ "Failed to read value at position " ++ show off ++ ":"+ putStrLn $ " " ++ show (e :: SomeException)+ if BS.length input <= 1+ then do putStrLn $ "End of file reached"+ return Nothing+ else do putStrLn $ "Trying at position " ++ show (off+1) ++ "."+ tryGet True (BS.tail input) (off+1)+ ) readTimeLog :: Binary a => FilePath -> IO (TimeLog a) readTimeLog filename = do
src/dump-main.hs view
@@ -7,13 +7,15 @@ import System.IO import qualified Data.Map as M import Data.Version (showVersion)+import Data.Maybe+import Control.Monad import TimeLog import Data import Paths_arbtt (version) -data Flag = Help | Version+data Flag = Help | Version | LogFile String deriving Eq versionStr = "arbtt-dump " ++ showVersion version@@ -27,13 +29,16 @@ , Option "V" ["version"] (NoArg Version) "show the version number"+ , Option "f" ["logfile"]+ (ReqArg LogFile "FILE")+ "use this file instead of ~/.arbtt/capture.log" ] main = do args <- getArgs- case getOpt Permute options args of- (o,[],[]) | Help `notElem` o && Version `notElem` o -> return ()+ flags <- case getOpt Permute options args of+ (o,[],[]) | Help `notElem` o && Version `notElem` o -> return o (o,_,_) | Version `elem` o -> do hPutStrLn stderr versionStr exitSuccess@@ -46,7 +51,9 @@ dir <- getAppUserDataDirectory "arbtt" -- let captureFilename = dir </> "capture.log"+ let captureFilename =+ fromMaybe (dir </> "capture.log") $ listToMaybe $+ mapMaybe (\f -> case f of { LogFile f -> Just f; _ -> Nothing}) $+ flags captures <- readTimeLog captureFilename :: IO (TimeLog CaptureData) mapM_ print captures
+ src/recover-main.hs view
@@ -0,0 +1,67 @@+module Main where+import System.Directory+import System.FilePath+import System.Console.GetOpt+import System.Environment+import System.Exit+import System.IO+import qualified Data.Map as M+import Data.Version (showVersion)+import Data.Maybe+import Control.Monad++import TimeLog+import Data++import Paths_arbtt (version)++data Flag = Help | Version | InFile String | OutFile String+ deriving Eq++versionStr = "arbtt-recover " ++ showVersion version+header = "Usage: arbtt-recover [OPTIONS...]"++options :: [OptDescr Flag]+options =+ [ Option "h?" ["help"]+ (NoArg Help)+ "show this help"+ , Option "V" ["version"]+ (NoArg Version)+ "show the version number"+ , Option "i" ["infile"]+ (ReqArg InFile "FILE")+ "read from this file instead of ~/.arbtt/capture.log"+ , Option "o" ["outfile"]+ (ReqArg OutFile "FILE")+ "write to this file instead of ~/.arbtt/capture.log.recovered"+ ]+++main = do+ args <- getArgs+ flags <- case getOpt Permute options args of+ (o,[],[]) | Help `notElem` o && Version `notElem` o -> return o+ (o,_,_) | Version `elem` o -> do+ hPutStrLn stderr versionStr+ exitSuccess+ (o,_,_) | Help `elem` o -> do+ hPutStr stderr (usageInfo header options)+ exitSuccess+ (_,_,errs) -> do+ hPutStr stderr (concat errs ++ usageInfo header options)+ exitFailure++ dir <- getAppUserDataDirectory "arbtt"++ let captureFilename =+ fromMaybe (dir </> "capture.log") $ listToMaybe $+ mapMaybe (\f -> case f of { InFile f -> Just f; _ -> Nothing}) $+ flags+ let saveFilename =+ fromMaybe (dir </> "capture.log.recovered") $ listToMaybe $+ mapMaybe (\f -> case f of { OutFile f -> Just f; _ -> Nothing}) $+ flags++ captures <- recoverTimeLog captureFilename :: IO (TimeLog CaptureData)+ writeTimeLog saveFilename captures