I recently decided to start doing more self-tracking. In my Org-mode workflow series, I gave a brief overview of how I did task management, but what I failed to mention then was that Org provides clocking capabilities, so I sort-of knew where I was spending my time. However, I wanted to track things that are unrelated to tasks. For instance, I wanted to track my mood at different times of the day, or what I ate. I also wanted to track numeric quantities: how much water did I drink? How far did I run? How long did I sleep?
In short, I wanted to create log entries for my life, from which I can later do aggregate analyses on (is my sleep adversely affected by the food I eat?). To my surprise, I could not find a simple tool that fit my needs. The tools I found were either:
- Too specific: these are apps specifically designed to track a certain action (e.g. water intake apps, fitness apps). I needed a consistent interface for tracking anything.
- Binary: Org-mode’s support for habit-tracking is limited to binary actions (e.g. did I exercise today?) Anything more complex required significant tooling. Creating log entries need to be low friction.
This motivated me to build a simple proof-of-concept logger, track. It also provided me an avenue to learn Rust, although in hindsight I didn’t make much progress on that front.
The Track File Syntax
The track file resembles logs you’d see in any software. It is an append-only file where each line is a log entry:
In square brackets we have the timestamp of the log entry. The log entry begins
with a category, separated from the log entry value by a colon: here it is
water. Categories can be arbitrarily complex. For example, for the exercises I
perform, I “group” them under the same category by giving them the categories
The log entry value can take on two forms. If the value begins with a digit,
track assumes that we wish to log a numerical quantity. In the log entry above,
the log entry has a quantity of
300, with units
The log entry could also be free-form text. This is for logging other random things, like mood. An example of such a log entry would be:
To enter a new entry, track exposes a simple command-line interface via
add, which takes two indexed arguments, the category, and the entry value.
track add water 300ml
Querying the Log
track supports a simple query interface of the form
track query category
num-days defaults to 7 (the past week). It:
- Filters for entries that are at most
num-daysback, and whose category contains
- Sums numerical quantities if the units match. For example, if there were
two entries on the same day, one for
water:300mland the other
water:600ml, track would report
This is what I see running
track query water on my 5 days of log entries.
~ on master [!] ❯ track query water 7 05 Oct 2020 water 1400ml 06 Oct 2020 water 1600ml 07 Oct 2020 water 1900ml 08 Oct 2020 water 2000ml 09 Oct 2020 water 1700ml
Entering Entries on the Go
All is well when I’m at my computer where I have access to a terminal, but what
about when I’m on the move? Because the log format is so simple, I shipped
track with a simple Telegram bot, that allowed me to add entries by sending
the bot an entry:
I host the Telegram bot on my DigitalOcean instance, and run
sshfs so that
all my writes go the remote track file as well.
Right now I have only been tracking for a short while, so I cannot yet comment whether it will be useful, but this certainly reduces the friction. I’m hoping to hook some things up so that automatic entries are created (e.g. amount of sleep, from my Xiaomi Miband).