C.W.K.
Stream
Lesson 04 of 05 · published

Recent Attempts Log — Spotting Patterns

~15 min · attempts-log, logging, patterns

Level 0Greenhorn
0 XP0/53 lessons0/14 achievements
0/100 XP to next level100 XP to go0% complete

The attempts log is your post-incident reading material and your weekly health check. The goal isn't to read every row — it's to make patterns visible at a glance.

The display

Last 100 rows, newest first, color-coded by success/failure. That's it.

Patterns to watch for

  • Bursts from one IP, then silence — hit your retry limit, got blacklisted. Working as intended.
  • Steady drip from many IPs — distributed scanner. Investigate WAF / fail2ban / change-port.
  • curl / python-requests / wget UAs — 100% bots. Your real traffic is browsers.
  • Successful login from an IP you don't recognize — STOP READING THIS DASHBOARD AND GO TO TRACK 7.

Retention

SQLite handles millions of rows without complaint, but UI gets useless past 100 visible. Keep all rows in DB (cheap forensics), display the last 100 by default, with a "load 500 more" button if you ever need to dig.

Code

Augment the security_attempts table with full audit fields·sql
-- Replace the lightweight counter table with a richer log
CREATE TABLE security_attempts (
  id            INTEGER PRIMARY KEY AUTOINCREMENT,
  ip            TEXT    NOT NULL,
  success       INTEGER NOT NULL,        -- 0 or 1
  attempted_at  INTEGER NOT NULL,        -- unix timestamp
  user_agent    TEXT,                    -- optional but useful
  reason        TEXT                     -- 'wrong_pin', 'blacklisted', 'rate_limited', 'success'
);
CREATE INDEX idx_attempts_time ON security_attempts(attempted_at);
CREATE INDEX idx_attempts_ip   ON security_attempts(ip);

External links

Exercise

Migrate from the simple counter to the richer attempts log (the schema above). Update increment_attempt to insert a new row instead of incrementing a counter, and re-define attempt_count(ip) as a 'count of failures in the last N seconds'. Render the log on the dashboard. Now you can see WHY each attempt was rejected, not just how many.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.