Firefox tabs analysis with Prometheus and Grafana

Observability in browsing sessions

Summary

In the last post on organizing Firefox tabs, I described how I work and thrive with 100-200 tabs opened, with hundreds more in saved sessions.

I wanted to have some numbers so I wrote a script and I use Prometheus and Grafana to display counts of Firefox tabs on graphs.

Grafana dashboard and numbers

This Grafana dashboard displays the count of Firefox tabs and windows over time.

The header of the dashboard is a current overview of Firefox windows, tabs and sessions.
The header of the dashboard is a current overview of Firefox windows, tabs and sessions.
On this typical day, my number of open active Firefox tabs varies between 37 and 70.
On this typical day, my number of open active Firefox tabs varies between 37 and 70.
I have 535 saved tabs in 32 windows in TabSessionManager.
I have 535 saved tabs in 32 windows in TabSessionManager.

Script

A cron job executes the script count-tabs.py every minute. It reads session and tabs information from JSON files under home the user directory. Then it writes metrics in Prometheus format to sys.stdout. The cron job redirects the output to a file that is read by the textfile collector in node_exporter. Prometheus scrapes the metrics and Grafana displays them.

Input:

  • Firefox sessionstore-backups file
  • TabSessionManager User Saves files

Output:

  • Metrics in Prometheus format
#!/usr/bin/python3

# https://alexandre.deverteuil.net/posts/firefox-tabs-analysis/

## root crontab:
# * * * * * /home/alex/Programs/count-tabs.py | sponge /usr/local/lib/node_exporter/firefox-tabs.prom
## `sponge` comes from the moreutils package.

import glob
import json
import os
import os.path
import sys

import lz4.block  # sudo dnf install python3-lz4


# https://unix.stackexchange.com/questions/385023/firefox-reading-out-urls-of-opened-tabs-from-the-command-line
def count_tabs_and_windows():
    userdir = os.path.expanduser("~alex")
    pattern = ".mozilla/firefox*/*.default*/sessionstore-backups/recovery.jsonlz4"
    matches = glob.glob(userdir + "/" + pattern)
    if len(matches) == 0:
        print_metrics(0, 0, 0, 0)
        sys.exit()
    else:
        sessionstore = matches[0]
        with open(sessionstore, "rb") as f:
            magic = f.read(8)
            session_data = json.loads(lz4.block.decompress(f.read()).decode("utf-8"))

    # Uncomment to dump the uncompressed JSON in sessions.json.
    #with open("sessions.json", "w") as f:
    #    f.write(json.dumps(jdata))

    group_tabs_count = 0
    active_tabs_count = 0
    inactive_tabs_count = 0
    windows_count = 0

    for win in session_data["windows"]:
        windows_count += 1
        for tab in win["tabs"]:
            i = int(tab["index"]) - 1
            url = tab["entries"][i]["url"]
            title = tab["entries"][i]["title"]
            if (url.find("grouptab/index.html") > 0 or
                url.find("grouptab-personal/index.html") > 0 or
                url.find("grouptab%2Findex.html") > 0 or
                url.find("grouptab-personal%2Findex.html") > 0
                ):
                group_tabs_count += 1
                #print("GROUP", title)
            elif url.startswith("moz-extension://"):
                inactive_tabs_count += 1
                #print("INACTIVE", title, url)
            else:
                active_tabs_count += 1
                #print("ACTIVE", title)

    metric_fmt = "firefox_session_open_tabs{{type=\"{type}\"}} {value}"
    print("# HELP firefox_session_open_tabs number of open tabs from Firefox")
    print("# TYPE firefox_session_open_tabs gauge")
    print(metric_fmt.format(type="grouptab", value=group_tabs_count))
    print(metric_fmt.format(type="active", value=active_tabs_count))
    print(metric_fmt.format(type="inactive", value=inactive_tabs_count))
    print("# HELP firefox_session_open_windows number of open Firefox windows")
    print("# TYPE firefox_session_open_windows gauge")
    print("firefox_session_open_windows", windows_count)


def count_saved_sessions():
    userdir = os.path.expanduser("~alex")
    pattern = "Downloads/TabSessionManager - Backup/User Save/*.json"
    session_files = glob.glob(userdir + "/" + pattern)
    sessions = {}

    for session_file in session_files:
        with open(session_file) as f:
            session_data = json.loads(f.read())[0]
        name = session_data['name']
        if session_data['tag']:
            tag = session_data['tag'][0]
        else:
            tag = "untagged"
        group_tabs_count = 0
        regular_tabs_count = 0
        for window in session_data['windows']:
            for tab in session_data['windows'][window]:
                url = session_data['windows'][window][tab]['url']
                if (url.find("grouptab/index.html") > 0 or
                    url.find("grouptab-personal/index.html") > 0
                    ):
                    group_tabs_count += 1
                else:
                    regular_tabs_count += 1
        sessions[name] = {
            'name': name,
            'tag': tag,
            'group_tabs_count': group_tabs_count,
            'regular_tabs_count': regular_tabs_count
        }

    print("# HELP firefox_saved_session_tabs number of tabs from Firefox saved session")
    print("# TYPE firefox_saved_session_tabs gauge")
    metric_fmt = "firefox_saved_session_tabs{{tag=\"{tag}\",session_name=\"{name}\",type=\"{type}\"}} {value}"
    for name in sessions:
        print(metric_fmt.format(name=name, tag=sessions[name]['tag'], type="grouptab", value=sessions[name]['group_tabs_count']))
        print(metric_fmt.format(name=name, tag=sessions[name]['tag'], type="regular", value=sessions[name]['regular_tabs_count']))


count_tabs_and_windows()
count_saved_sessions()

Example metrics output

# HELP firefox_session_open_tabs number of open tabs from Firefox
# TYPE firefox_session_open_tabs gauge
firefox_session_open_tabs{type="grouptab"} 25
firefox_session_open_tabs{type="active"} 22
firefox_session_open_tabs{type="inactive"} 73

# HELP firefox_session_open_windows number of open Firefox windows
# TYPE firefox_session_open_windows gauge
firefox_session_open_windows 6

# HELP firefox_saved_session_tabs number of tabs from Firefox saved session
# TYPE firefox_saved_session_tabs gauge
firefox_saved_session_tabs{tag="client",session_name="xxxxx",type="grouptab"} 3
firefox_saved_session_tabs{tag="client",session_name="xxxxx",type="regular"} 14
firefox_saved_session_tabs{tag="client",session_name="yyyyyyyyyyy",type="grouptab"} 1
firefox_saved_session_tabs{tag="client",session_name="yyyyyyyyyyy",type="regular"} 3
firefox_saved_session_tabs{tag="Grafana",session_name="Grafana: main",type="grouptab"} 1
firefox_saved_session_tabs{tag="Grafana",session_name="Grafana: main",type="regular"} 6
Alexandre de Verteuil
Alexandre de Verteuil
Senior Solutions Architect

I teach people how to see the matrix metrics.
Monkeys and sunsets make me happy.

Related