Python › Module 3 › Lesson 3
Log Parser Script
Parse text logs line-by-line to count errors, failed logins, or suspicious IPs
Opening
grep finds one night. A parser counts a week — on a copy YOU created, not a production scrape.
Module 1’s first script already printed lines containing Failed password. That is hunting. This lesson is accounting: open the file, walk every line, increment a counter when a needle matches, optionally remember a field (an IP) so you can rank talkers. Humans miss the third duplicate at 02:00. A for-loop does not. The mechanism is almost boring on purpose: with open(...) as f, for line in f, if needle in line. Start with a substring. Regex waits until the next module, when the field sits in a messy place. collections.Counter waits until the lab, when you rank IPs. The ethical object is a fictional sample_auth.log YOU write in $HOME/cyberlium-lab. Documentation IPs (203.0.113.0/24, 198.51.100.0/24, 192.0.2.0/24) are labels in a story, not people to deanonymize and not hosts to scan. You do not pull production auth logs without a ticket and written authorization. You do not wget a company’s log server “for realism.” You do not publish the sample as if it were a real breach. Next lesson’s lab builds the analyzer (counts + Counter of IPs + chmod 600) on that same fictional file.
1. Line-by-line is the whole engine: open, test, count, close
A text log is a sequence of lines. A parser is a loop that asks a yes/no question of each line and sometimes pulls a slice. with open(path, encoding="utf-8", errors="ignore") as f keeps the handle from leaking if you hit a bad byte — logs are messy; errors="ignore" is a teaching choice so a single corrupt character does not abort the count. for line in f reads lazily. You do not f.read() a multi-gigabyte file into one string on a laptop as the first move. if "Failed password" in line is a substring filter: cheap, readable, good enough until two different messages share the words. count += 1 is the report. print the total. That is a parser. Everything fancier (regex groups, Counter, CSV output) is the same loop with more memory of what it saw.
Work on a copy. The only copy of a log is evidence and an operational file; a parser bug that truncates on write is how people destroy the only trail. In this course you never had production. You create the sample. If you later have authorization to export, you export, you parse the export, you leave the live file alone. You do not open the live path with mode "w". You do not delete lines that matched to “clean up.” You do not email the full log to a public list to get help. Counts and top-IP lists can go in chmod 600 notes. Full dumps of real users do not go on GitHub.
2. What you count: failures, errors, talkers — not identities of strangers
Failed password lines are a teaching stand-in for “auth failure.” Error and panic strings are the same idea with a different needle. Suspicious IPs in this course means “addresses that appear often in MY sample,” ranked so you see a spray-shaped pattern in fiction. It does not mean geo-lookup, WHOIS harassment, or knocking on the address with Module 2’s scanner. A documentation IP that failed twenty times in your sample is a Counter lesson, not a person. Do not treat RFC 5737 / TEST-NET addresses as attackers to pursue. Do not paste real customer IPs from a job into the lab file “to make it realistic.” Invent the lines. Keep usernames fictional (root, admin, alice) so you are not practicing on a roster.
Password spraying in a real SOC is a pattern: many usernames, few passwords, many failures from one source. Your parser can count failures per IP once the lab extracts the address. That count is a hint for a human, not a green light to lock a production account or to scan the source. False positives exist: a misconfigured printer, your own lab VM, a user who forgot a rotation. The script does not know. You already learned that automation reports; it does not isolate. Keep that split when the numbers look exciting.
3. Substring first; regex later; never “parse” by attacking the host
Needle in line fails when the interesting field moves or when Failed password appears in a comment. Regex (Module 4) extracts with groups: the IP after from , a status code, a username. You will still test on five to ten sample lines you own, not on a firehose of other people’s traffic. Do not overfit a regex to one vendor’s format and then declare all logs parsed. Do not use a parser as cover to netcat the IP you just extracted. Extraction is not authorization to connect. Module 2 already limited sockets to localhost; that limit does not expire because a log line named 203.0.113.10.
4. Wrong vs right: scraping production and stalking IPs vs parsing YOUR sample
Worked failure — same loop, opposite data source. Right never includes unauthorized log collection or deanonymizing people.
Wrong
scp production /var/log/auth.log without a ticket. Scrape a company’s log endpoint because you found it in a search. Commit real user logs to git. Geo-locate extracted IPs and message the ISP. Scan the IPs with the Module 2 scanner. Delete the original log after a bad write. Publish the sample as a “breach dump.” Parse in order to build a spray list of usernames for Hydra. This course forbids all of that.
Right
Create fictional sample_auth.log in $HOME/cyberlium-lab with documentation IPs. Count Failed password with a line loop. Work on that copy. Write counts (not a real-user dump) to chmod 600 notes. Treat IPs as labels in a story, not people to pursue. Next lesson’s lab adds Counter of those IPs on the same fictional file.
5. Practical: write sample_auth.log and count failures — copy, parse, report
The file below is teaching fiction. Type it yourself (or redirect it) into cyberlium-lab. Run the counter. Record the number in notes. Do not replace the lines with a log from work. Do not add real coworker names. chmod 600 the sample and the notes — even fiction can sit next to other lab files that are more sensitive.
Create YOUR sample_auth.log and count Failed password lines
# FICTIONAL log YOU create. Do NOT scrape production.
# IPs are documentation ranges — not people to deanonymize or scan.
mkdir -p "$HOME/cyberlium-lab"
cd "$HOME/cyberlium-lab"
cat > sample_auth.log << 'LOG'
sshd: Failed password for root from 203.0.113.10 port 44022
sshd: Accepted password for alice from 192.0.2.10 port 51111
sshd: Failed password for admin from 203.0.113.10 port 44023
sshd: Failed password for root from 198.51.100.8 port 51234
sshd: Failed password for root from 203.0.113.10 port 44024
sshd: Accepted password for alice from 192.0.2.10 port 51112
sshd: Failed password for ubuntu from 198.51.100.8 port 51235
sshd: Failed password for root from 203.0.113.10 port 44025
LOG
cat > count_failures.py << 'PY'
path = "sample_auth.log"
needle = "Failed password"
count = 0
with open(path, encoding="utf-8", errors="ignore") as f:
for line in f:
if needle in line:
count += 1
print("failures:", count)
# Next lesson: Counter of source IPs on this same fictional file.
PY
python3 count_failures.py
NOTES="$HOME/cyberlium-lab/log-parse-notes.txt"
{
echo "=== LOG PARSE NOTES ==="
echo "source: fictional sample_auth.log I created (not production)"
echo "method: line-by-line; substring Failed password"
echo "failures_count: (fill after run)"
echo "ethics: no scrape, no scan of extracted IPs, no real user dump in git"
} > "$NOTES"
chmod 600 sample_auth.log count_failures.py "$NOTES"
# Windows without chmod: WSL/Git Bash, or restrict the files in your profile.
# NEVER: copy /var/log/auth.log from a job into this folder without authorization
# NEVER: nmap the from-addresses
# NEVER: treat 203.0.113.10 as a personMission: fictional sample_auth.log + failure count in locked notes
1) Create YOUR own sample_auth.log in $HOME/cyberlium-lab with fictional users and documentation IPs. 2) Run a line-by-line substring count of Failed password (or an equivalent failure needle). 3) Write the count and the ethics line (copy, not prod; no scanning IPs; no real dumps) to log-parse-notes.txt and chmod 600 the sample, script, and notes. Never scrape production. Never deanonymize people from addresses in a sample.
Stuck? Ask Cyberlium AI Mentor
If “I should use a real auth.log so the counts matter” still feels true, ask for a hint — not a scrape. Try: "Hint only: why does a line-by-line substring count on MY fictional sample teach the same mechanism as a SOC export, and why must I not scan or WHOIS the documentation IPs I wrote?" You still create the file. No production logs, no Hydra on extracted users.
You now treat a log as lines you loop, a needle you test, and a count you report — on a copy you created. Substring first. IPs are labels, not targets. Production stays behind authorization. Next — Lab: Build a Log Analyzer — the same fictional file, plus Counter of source IPs, a short summary, and chmod 600 on everything in cyberlium-lab.
Knowledge Check
APPLY: You have count_failures.py and a classmate offers a “real” auth.log from their employer’s jump host so your counts look impressive. What do you parse, and why?
Multiple choice
Knowledge Check
APPLY: Your sample shows twenty Failed password lines from 203.0.113.10. Best next step in this course?
Multiple choice
Knowledge Check
APPLY: True or False: A parser should open the only live production log with write mode so it can delete matched lines after counting, and substring search is useless because only regex is professional.
True or False