The rollup counts the tags on posted links, and the pulse has a right-now
Reddit and BoardGameGeek send no referrer, so a visitor from either looks direct. A ?ref=<name> on the posted link says where they came from; the rollup counts those (one per address per day, Facebook's fbclid as its own) beside the referrers browsers do send. The pulse gains a right-now recipe: live sockets, rooms touched in the last hour, and today's partial row. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jm2auWk6RP71CjaAb4FMoG
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
ac2c3576a7
commit
cf7920e159
@@ -40,7 +40,15 @@ quiet, say so in one line before the details.
|
||||
serviceStarts, ledgerMB). Report day-over-day direction, not raw
|
||||
rows. Its Sentry cron monitor is slug `wizwar-rollup` (a missed
|
||||
check-in there means the rollup itself is broken). Re-roll a day by
|
||||
hand: `wizwar-rollup.sh YYYY-MM-DD`.
|
||||
hand: `wizwar-rollup.sh YYYY-MM-DD`. `campaigns` counts visitors
|
||||
(one per address per day) whose link carried `?ref=<name>` — the tags
|
||||
on Eric's posts (reddit, bgg, …) — or a Facebook fbclid; referrers
|
||||
alone can't attribute Reddit or BGG, which send none.
|
||||
**Right now** (on request, or when the announcement is fresh): live
|
||||
sockets `ss -tn state established '( sport = :8787 )' | tail -n +2 | wc -l`,
|
||||
rooms touched in the last hour `find /var/lib/wizwar/rooms -name '*.jsonl' -mmin -60 | wc -l`,
|
||||
and today so far `wizwar-rollup.sh $(date -u +%F)` (a partial row,
|
||||
replaced again at 00:10; the vitals in it are the moment's).
|
||||
5. **The table itself**:
|
||||
- Room count and growth: `ls /var/lib/wizwar/rooms/*.jsonl | wc -l`
|
||||
- New human names this week: room ledgers' join lines minus bots
|
||||
|
||||
+13
-2
@@ -3,7 +3,9 @@
|
||||
# yesterday's traffic (from Caddy's access log), the table's growth (from
|
||||
# the room ledgers, stats.json and feedback.jsonl), and the box's vitals.
|
||||
# Counts only: no addresses are kept. The pulse reads it for trends the
|
||||
# self-rotating access log cannot keep.
|
||||
# self-rotating access log cannot keep. Referrers are what browsers send
|
||||
# (Reddit and BGG send none); campaigns are the ?ref=<name> tags on links
|
||||
# Eric posts, one count per address per day, plus Facebook's fbclid.
|
||||
# Cron: 10 0 * * * (UTC), see /etc/cron.d/wizwar-rollup (deploy.sh installs both).
|
||||
# Sentry Crons check-in: /root/.wizwar-sentry-cron-rollup holds the URL
|
||||
# (absent = no check-ins).
|
||||
@@ -25,6 +27,9 @@ BOT = ("bot", "crawl", "spider", "facebookexternalhit", "slack", "discord", "twi
|
||||
# --- traffic: every access log file touched since the day began ---
|
||||
req = 0; human = 0; bot = 0; hips = set(); bips = set()
|
||||
paths = collections.Counter(); status = collections.Counter(); refs = collections.Counter(); ws = 0
|
||||
# Where a visit came from, when the link itself says so: ?ref=<name> on a
|
||||
# link Eric posted, a Facebook click's fbclid, or a utm_source.
|
||||
campaigns = collections.Counter(); seen_campaign = set()
|
||||
for f in sorted(glob.glob("/var/lib/caddy/access*.log*")):
|
||||
if os.path.getmtime(f) < t0: continue
|
||||
opener = gzip.open if f.endswith(".gz") else open
|
||||
@@ -41,8 +46,13 @@ for f in sorted(glob.glob("/var/lib/caddy/access*.log*")):
|
||||
req += 1
|
||||
if isbot: bot += 1; bips.add(ip)
|
||||
else: human += 1; hips.add(ip)
|
||||
uri = q.get("uri", "").split("?")[0]
|
||||
full = q.get("uri", ""); uri = full.split("?")[0]
|
||||
if uri == "/ws": ws += 1
|
||||
if not isbot and "?" in full and ip not in seen_campaign:
|
||||
qs = dict(kv.split("=", 1) if "=" in kv else (kv, "") for kv in full.split("?", 1)[1].split("&"))
|
||||
tag = qs.get("ref") or qs.get("utm_source") or ("facebook" if "fbclid" in qs else None)
|
||||
if tag and re.fullmatch(r"[a-z0-9_-]{1,24}", tag):
|
||||
campaigns[tag] += 1; seen_campaign.add(ip)
|
||||
key = ("/clips" if uri.startswith("/clips") else "/watch" if uri.startswith("/watch")
|
||||
else "(assets)" if uri.startswith("/assets") or re.search(r"\.(png|jpg|svg|ico|css|js|webmanifest|mp4)$", uri)
|
||||
else uri if uri in ("/", "/ws", "/robots.txt") else "(other)")
|
||||
@@ -99,6 +109,7 @@ row = {
|
||||
"day": day, "requests": req, "human": human, "bot": bot,
|
||||
"humanAddresses": len(hips), "botAddresses": len(bips), "socketConnects": ws,
|
||||
"paths": dict(paths.most_common()), "status": dict(status), "referrers": dict(refs.most_common(10)),
|
||||
"campaigns": dict(campaigns.most_common(10)),
|
||||
"newRooms": new_rooms, "humanSeats": sum(seats.values()), "humanNames": sorted(seats),
|
||||
"gamesFinishedTotal": stats.get("gamesFinished"), "gamesCreatedTotal": stats.get("gamesCreated"),
|
||||
"reports": reports, "replies": replies,
|
||||
|
||||
Reference in New Issue
Block a user