Text and files in both
The log file
The task is the smallest useful script: read an access log, count the lines that ended with a server error, write the count into a report and print it. The same five lines of log feed both versions.
access.log
127.0.0.1 - - [04/Nov/2026:10:00:00 +0000] "GET /index.html HTTP/1.1" 200 512
127.0.0.1 - - [04/Nov/2026:10:00:01 +0000] "GET /missing HTTP/1.1" 404 153
127.0.0.1 - - [04/Nov/2026:10:00:02 +0000] "GET /boom HTTP/1.1" 500 0
127.0.0.1 - - [04/Nov/2026:10:00:03 +0000] "POST /save HTTP/1.1" 500 0
127.0.0.1 - - [04/Nov/2026:10:00:04 +0000] "GET /index.html HTTP/1.1" 200 512
Ruby
lines = File.readlines("access.log")
errors = lines.count { |line| line.include?(" 500 ") }
File.write("report.txt", "errors: #{errors}\n")
puts errors
ruby count.rb
2
The report it wrote
cat report.txt
errors: 2
Python
from pathlib import Path lines = Path("access.log").read_text().splitlines() errors = sum(1 for line in lines if " 500 " in line) Path("report.txt").write_text(f"errors: {errors}\n") print(errors)
python3 count.py
2
The report it wrote
cat report.txt
errors: 2
Both scripts print the same number and leave the same file behind. The next run of either one overwrites the report, which is the behaviour the task wants and a good reason to keep the output path in one place.
What differs
- The file API. Ruby has File.readlines and File.write on the class itself. Python usually goes through pathlib.Path, which ties the path and the read together: Path("access.log").read_text(). Both are in the standard library.
- Counting. Ruby's count takes a block and reads as a sentence. Python has no block syntax, so the same idea is sum(1 for line in lines if ...): a generator expression inside a call.
- Line endings. readlines keeps the \n at the end of each line; Python's splitlines() drops it. A == comparison on the whole line works in Python and fails in Ruby until the line is chomped, which is why the Ruby version tests include? here.
Neither API is faster in a way this task can see; both read the file in one go. For a file that does not fit in memory, both languages offer a line-by-line loop, and that is the version to write when the log is a gigabyte.
Next: HTTP and JSON in both
Article author: Arthur Isaev