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.
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