Reading Logs Like a Pro
Part of Day One
This is the fifth article in the Day One: Getting Started series. You should have already completed Getting Access, Orientation, Understanding Your Permissions, and Safe Exploration.
Something broke. The app is throwing errors. Users are complaining. Your team lead says, "Can you check the logs?"
And now you're staring at files full of timestamps and cryptic messages wondering where to even begin.
Let's fix that.
Reading logs is probably the most important skill for debugging production systems. Once you get comfortable with it, you'll be able to diagnose problems in minutes instead of hours.
The Investigation Workflow
graph TD
A["🚨 Something Is Broken"] --> B["Find the Logs<br/>ls -la /var/log/"]
B --> C["View Recent Entries<br/>tail -100 logfile"]
C --> D["Search for Errors<br/>grep -i error logfile"]
D --> E{"Pattern Found?"}
E -->|Yes| F["Narrow the Time Window<br/>journalctl --since"]
E -->|No| G["Check Service Logs<br/>journalctl -u service"]
G --> D
F --> H["✅ Root Cause Identified"]
style A fill:#c92a2a,stroke:#ff6b6b,color:#fff
style H fill:#2f9e44,stroke:#51cf66,color:#fff
style B fill:#2b6cb0,stroke:#2c5282,color:#fff
style C fill:#2b6cb0,stroke:#2c5282,color:#fff
style D fill:#2b6cb0,stroke:#2c5282,color:#fff
style E fill:#d97706,stroke:#b45309,color:#fff
style F fill:#2b6cb0,stroke:#2c5282,color:#fff
style G fill:#2b6cb0,stroke:#2c5282,color:#fff
Where Are the Logs?
Most logs live in /var/log/:
Common log files:
| Log File | What It Contains |
|---|---|
/var/log/syslog or /var/log/messages |
General system logs |
/var/log/auth.log or /var/log/secure |
Authentication (logins, sudo) |
/var/log/dmesg |
Kernel messages (hardware, boot) |
/var/log/nginx/ |
Nginx access and error logs |
/var/log/apache2/ |
Apache logs |
/var/log/mysql/ |
MySQL/MariaDB logs |
Application-specific logs often live in:
/var/log/appname//opt/appname/logs//home/appuser/logs/- Wherever the app was configured to write them
Ask your team: "Where do the application logs live?" Every app is different.
Reading Common Log Formats
Before reaching for tail or grep, it helps to know what you're looking at. Log formats vary by application — here are the three most common:
General system events from Linux itself and most services follow this format:
| Part | Meaning |
|---|---|
Jan 15 14:23:45 |
Timestamp |
prod-web-01 |
Hostname (useful when logs are aggregated from multiple servers) |
nginx[1234] |
Service name and process ID |
Everything after : |
The actual message |
Every HTTP request to your server leaves a line here:
192.168.1.50 - - [15/Jan/2024:14:23:45 +0000] "GET /api/users HTTP/1.1" 200 1234 "-" "Mozilla/5.0..."
| Part | Meaning |
|---|---|
192.168.1.50 |
Client IP address |
[15/Jan/2024:14:23:45 +0000] |
Timestamp |
"GET /api/users HTTP/1.1" |
HTTP method, path, and protocol |
200 |
HTTP status code |
1234 |
Response size in bytes |
What to look for:
4xxcodes — Client errors (404 not found, 401 unauthorized)5xxcodes — Server errors (500 internal error, 502 bad gateway)
When something goes wrong server-side, it ends up here:
2024/01/15 14:23:45 [error] 1234#0: *5678 connect() failed (111: Connection refused) while connecting to upstream
Unlike access logs, error logs are descriptive — the [error] level and the message tell you directly what went wrong. Look for words like failed, refused, timeout, and upstream.
The Essential Log Commands
When to use: Something just broke and you want to see the last few dozen log lines.
Most recent entries are at the bottom of a log file — start there:
Key insight: The number after tail controls how many lines you see. Start with 20-50 for a quick look; go up to 500 if the problem started a while ago.
When to use: You want to reproduce the problem and watch errors appear in real-time.
This is the killer feature — new log entries appear as they're written:
Trigger the problem (refresh the page, make an API call) and watch the entries appear live. Press Ctrl+C to stop.
Follow multiple logs at once:
Key insight: Following multiple logs simultaneously lets you correlate access requests with errors — you can see which request triggered which error.
When to use: The log file is huge and you need to scroll around, search, or read it like a document.
Navigation inside less:
| Key | Action |
|---|---|
G |
Jump to end (most recent entries) |
g |
Jump to beginning |
/error |
Search forward for "error" |
n |
Next search match |
N |
Previous search match |
q |
Quit |
Key insight: Press G immediately after opening a large log to jump to the most recent entries — you almost never want to start at the beginning.
When to use: You want to know when a log file was created, or check the log format before diving in.
Key insight: head is most useful for confirming the timestamp format a log uses before you try to grep for a specific time window — log formats vary between applications.
Searching Logs with grep
grep is your search tool — it finds lines in a log file that match a pattern. Here are the flags you'll reach for most often:
| Flag | What It Does |
|---|---|
-i |
Case-insensitive (error, Error, ERROR all match) |
-C N |
Show N lines of Context before AND after each match |
-B N |
Show N lines Before each match |
-A N |
Show N lines After each match |
-c |
Count matches instead of printing them |
-m N |
Stop after the first N matches |
-r |
Search recursively through a directory |
--line-buffered |
Flush output immediately (required when piping to another command) |
Find All Errors
When to use: You want to see every line in a log file that mentions an error.
Key insight: Always use -i unless you're intentionally filtering by case — logs are inconsistent about capitalisation (error, Error, and ERROR all appear in the wild).
Find Errors with Context
When to use: You found an error but need to understand what led up to it. Errors rarely happen in isolation.
-C 3 shows 3 lines before AND after each match. Use -B and -A separately when you need asymmetric context:
Key insight: The lines before an error are often more informative than the error line itself — they show what the system was doing when it failed.
Recent Errors Only
When to use: The log file has been running for weeks and you only care about recent activity. Grepping a multi-gigabyte log is slow and buries current errors in historical noise.
Key insight: tail limits the data before grep even runs. Adjust the number to match how far back you need — tail -100 for a quick check, tail -2000 on a busy server where the problem started an hour ago.
Find by Timestamp
When to use: You know roughly when something happened and want to narrow the search to that window.
First, check the timestamp format in your log — it varies between applications, and this is exactly where checking the format first with head pays off:
Then grep for entries in that window:
Key insight: Be as specific as the format allows. grep "14:" is too broad; grep "Jan 15 14:3" narrows to a 10-minute window. For journalctl-managed logs, --since and --until (covered below) are usually easier.
Search Multiple Files
When to use: You're not sure which log file contains the error, or you want to sweep an entire log directory at once.
Key insight: -r prefixes every match with its filename — useful for discovering which log file is actually capturing the errors you're hunting.
Count Occurrences
When to use: You want to gauge the scale of a problem before diving into the details.
Key insight: Start with -c to understand severity. Three occurrences might be noise; 47 in the last hour is worth dropping everything for. Once you know the scale, remove the -c to read the actual lines.
journalctl - The Modern Log Tool
On systems using systemd (most modern Linux), journalctl is incredibly powerful.
Access Requirements
On many systems, journalctl without sudo only shows logs for your own user. If you're getting empty output or "permission denied" errors, either run it with sudo, or ask your team to add you to the systemd-journal group — which grants read access to all system logs without needing full sudo.
View All Recent Logs
Shows the last 50 log entries from all services.
Follow Logs in Real-Time
Like tail -f but for all system logs at once.
View Logs for a Specific Service
This is where journalctl shines:
Logs Since a Specific Time
Show Only Errors and Warnings
Priority levels: emerg, alert, crit, err, warning, notice, info, debug
Combine Service and Time
This command says: "Show me nginx errors from the last hour."
Log Analysis Patterns
Pick the scenario that matches your situation:
Goal: Find out what was happening on the server around a specific time.
Or grep a log file directly if you know the format:
Key insight: Check the log format first (with head) so you know what timestamp pattern to grep for — it varies between applications.
Goal: Find which error is happening most often so you know where to start.
grep -i "error" /var/log/app/error.log | sort | uniq -c | sort -rn | head -20
What this does: sort groups identical lines together, uniq -c counts them, sort -rn puts the most frequent first. Start investigating from the top.
Goal: Find the very first occurrence of an error to establish a timeline.
-m 1 stops after the first match — without it, grep would print every occurrence. Once you have a timestamp, you can correlate it with deployments, config changes, or traffic spikes.
Goal: Watch live to see if errors are still occurring right now.
--line-buffered ensures matches appear immediately rather than waiting for a full buffer. If no new lines appear after reproducing the problem, you may be looking at the wrong log file.
Accessing Protected Logs
Some logs are owned by root or a restricted group and will return "Permission denied" when you try to read them directly. You have two options:
Or, if you're in the adm group, you already have read access to most system logs without needing sudo. Check with groups — if adm isn't listed, ask your team to add you. See Understanding Your Permissions for how groups and log access work together.
Quick Reference
Most Used Commands
# Last 100 lines of a log
tail -100 /var/log/syslog
# Follow log in real-time
tail -f /var/log/nginx/error.log
# Search for errors
grep -i "error" /var/log/syslog
# Service logs (systemd)
journalctl -u nginx -n 100
# Recent errors only
journalctl --since "1 hour ago" -p err
# Follow service logs
journalctl -u nginx -f
Log Locations Cheat Sheet
| What You're Looking For | Where to Look |
|---|---|
| General system events | /var/log/syslog or journalctl |
| Authentication/logins | /var/log/auth.log or journalctl -u sshd |
| Web server | /var/log/nginx/ or /var/log/apache2/ |
| Database | /var/log/mysql/ or journalctl -u mysql |
| Application | Ask your team! |
Practice Exercises
Exercise 1: Find Recent Authentication Failures
You've been told that someone may be attempting to brute-force SSH logins. Check the last 200 lines of /var/log/auth.log and search for failed login attempts.
Hint: Pipe tail into grep. The word to search for is "Failed".
Which log file?
On Debian/Ubuntu, authentication events are in /var/log/auth.log. On RHEL/CentOS/Fedora, the same file is /var/log/secure. Either way, the grep command and output are identical.
Exercise 2: Find the Most Frequent Errors Today
The app has been logging errors all day. Use journalctl to get today's errors for the nginx service, then find which error message appears most often.
Hint: Combine journalctl, grep, sort, uniq -c, and sort -rn.
Exercise 3: Investigate a Time Window
Your team lead says the app started throwing errors around 2:30pm. Use journalctl to show all system logs from 2:25pm to 2:40pm today.
Hint: Use --since and --until with time strings.
Quick Recap
Start with the basics:
tail -f /var/log/app.log— Watch in real-timegrep "error"— Find the bad stuffjournalctl -u servicename— Service-specific logs
Add context:
- Use
-Band-Awith grep for surrounding lines - Use
--sincewith journalctl for time windows - Combine
tailandgrepfor recent errors
Think like a detective:
- When did it start?
- How often is it happening?
- What's the pattern?
Further Reading
Command References
man tail— Full options fortail;--retryis useful when following logs that rotate during an activetail -fman journalctl— Comprehensive reference; the-ooutput format options and--output-fieldsare particularly powerfulman grep— Full grep documentation;-Cfor context lines,-Pfor Perl-compatible regex in complex patterns
Deep Dives
- Brendan Gregg - Linux Performance — When logs point to performance issues, this is the definitive next stop
Official Documentation
- systemd journalctl — Authoritative journalctl reference from the systemd project
- Red Hat: Viewing and Managing Log Files — RHEL-specific log management guide
Related Articles
- Orientation — Covers
hostnameand system identification if you're not sure which server's logs you're looking at - Safe Exploration — Finding where application logs are stored on an unfamiliar server
What's Next?
You can read logs like a pro. The next skill is knowing where to find the team wiki, runbooks, and who to ask when logs alone aren't enough. Finding Documentation is coming soon. In the meantime, head back to the Day One Overview to review the full series.
Logs Tell Stories
Every log entry is a breadcrumb. Errors rarely happen in isolation — there's usually a chain of events. Learn to read that story, and debugging becomes much easier.