Is there software which time- tracks window & application usage?


EDIT: a version of the script with sorted reports can be found here


Always fun to write a script for it!

The script below will produce an output (report) like:

------------------------------------------------------------
nautilus
0:00:05 (3%)
------------------------------------------------------------
   0:00:05 (3%)     .usagelogs
------------------------------------------------------------
firefox
0:01:10 (36%)
------------------------------------------------------------
   0:00:05 (3%)     The Asker or the Answerer? - Ask Ubuntu Meta - Mozilla Firefox
   0:00:15 (8%)     scripts - Is there software which time- tracks window & application usage? - Ask Ubuntu - Mozilla Firefox
   0:00:10 (5%)     Ask Ubuntu - Mozilla Firefox
   0:00:15 (8%)     Why is a one line non-understandable answer used as review audit? - Ask Ubuntu Meta - Mozilla Firefox
   0:00:20 (10%)    bash - How to detect the number of opened terminals by the user - Ask Ubuntu - Mozilla Firefox
   0:00:05 (3%)     BlueGriffon - Mozilla Firefox
------------------------------------------------------------
gedit
0:02:00 (62%)
------------------------------------------------------------
   0:02:00 (62%)    2016_06_04_10_33_29.txt (~/.usagelogs) - gedit

============================================================
started: 2016-06-04 10:33:29    updated: 2016-06-04 10:36:46
============================================================


..which is updated once per minute.

Notes

  • The report will possibly report windows under the category: "Unknown". This is the case when windows have pid 0 (tkinter windows, such as Idle windows, aPython IDE). Their window title and usage will be reported correctly however.

  • The lock screen with password input is reported a "nux input window".

  • The percentages are rounded percentages, which might occasionally lead to minor differences between the application's percentage and the sum of its window's percentage.

    An example: If an application has two windows used, each used 0,7% of the total time, both windows will report 1% each (0.7 --> rounded to 1), while the application's usage reports 1% (1.4 --> rounded to 1)

    No need to say that these differences are totally irrelevant in the whole picture.

The script

#!/usr/bin/env python3
import subprocess
import time
import os

# -- set update/round time (seconds)
period = 5
# -- 
# don change anything below
home = os.environ["HOME"]
logdir = home+"/.usagelogs"

def currtime(tformat=None):
    return time.strftime("%Y_%m_%d_%H_%M_%S") if tformat == "file"\
           else time.strftime("%Y-%m-%d %H:%M:%S")

try:
    os.mkdir(logdir)
except FileExistsError:
    pass

# path to your logfile
log = logdir+"/"+currtime("file")+".txt"; startt = currtime()

def get(command):
    try:
        return subprocess.check_output(command).decode("utf-8").strip()
    except subprocess.CalledProcessError:
        pass

def time_format(s):
    # convert time format from seconds to h:m:s
    m, s = divmod(s, 60); h, m = divmod(m, 60)
    return "%d:%02d:%02d" % (h, m, s)

def summarize():
    with open(log, "wt" ) as report:
        totaltime = sum([it[2] for it in winlist])
        report.write("")
        for app in applist:
            wins = [r for r in winlist if r[0] == app]
            apptime = sum([it[2] for it in winlist if it[0] == app])
            appperc = round(100*apptime/totaltime)
            report.write(("-"*60)+"\n"+app+"\n"+time_format(apptime)+\
                         " ("+str(appperc)+"%)\n"+("-"*60)+"\n")
            for w in wins:
                wperc = str(round(100*w[2]/totaltime))
                report.write("   "+time_format(w[2])+" ("+\
                             wperc+"%)"+(6-len(wperc))*" "+w[1]+"\n")
        report.write("\n"+"="*60+"\nstarted: "+startt+"\t"+\
                     "updated: "+currtime()+"\n"+"="*60)

t = 0; applist = []; winlist = []
while True:
    time.sleep(period)
    frpid = get(["xdotool", "getactivewindow", "getwindowpid"])
    frname = get(["xdotool", "getactivewindow", "getwindowname"])
    app = get(["ps", "-p", frpid, "-o", "comm="]) if frpid != None else "Unknown"
    # fix a few names
    if "gnome-terminal" in app:
        app = "gnome-terminal"
    elif app == "soffice.bin":
        app = "libreoffice"
    # add app to list
    if not app in applist:
        applist.append(app)
    checklist = [item[1] for item in winlist]
    if not frname in checklist:
        winlist.append([app, frname, 1*period])
    else:
        winlist[checklist.index(frname)][
            2] = winlist[checklist.index(frname)][2]+1*period
    if t == 60/period:
        summarize()
        t = 0
    else:
        t += 1

How to set up

  1. The script needs xdotool to get the window's information

    sudo apt-get install xdotool
    
  2. Copy the script into an empty file, save it as window_logs.py

  3. Test- run the script: tart the script by the command (from a terminal):

    python3 /path/to/window_logs.py
    

    After one minute, the script creates a log file with the first results in ~/.usagelogs. The file is time- stamped with the creation date & time. The file is updated once per minute.

    At the bottom of the file, you can see both the start- time and the time-stamp of the latest edit. This way you can always see what is the file's time span.

    If the script restarts, a new file with a new (start-) time stamp is created.

  4. If all works fine, add to Startup Applications: Dash > Startup Applications > Add. Add the command:

    /bin/bash -c "sleep 15 && python3 /path/to/window_logs.py"
    

More notes

  • ~/.uselogs is a hidden directory by default. Press (in nautilus) Ctrl+H to make it visible.
  • As it is, the script rounds the window's activeness on 5 seconds, assuming less then 5 seconds is not really using the window. If you'd like to change the value, set it in the head of the script in the line:

    # -- set update/round time (seconds)
    period = 5
    # -- 
    
  • The script is extremely "low on juice". Furthermore, since the time- updates per window are done inside the script, the number of lines in the log file is limited to the actual number of used windows.

    Nevertheless, I wouldn't run the script for weeks in a row for example, to prevent accumulating too many lines (=window records) to maintain.


there is arbtt that does exactly what you describe: https://www.joachim-breitner.de/blog/336-The_Automatic_Rule-Based_Time_Tracker

update: this project is still alive (Oct 2020) and the arbtt home page here: http://arbtt.nomeata.de/

the github project is here: https://github.com/nomeata/arbtt