A cat /var/log/syslog on an active server mostly gives one thing: too many lines. When a service fails or an error recurs, first look for the service name, the time, and the exact message. grep helps reduce the noise without losing the lines that explain what happened just before.
This method works on a file under /var/log as well as on the output of journalctl. It does not replace the complete log: it serves to find a reliable starting point, then to expand around that point.

Start with a readable search
Add line numbers and ignore case if the program mixes Error, ERROR, or error:
grep -n -i 'error' /var/log/my-service.log
-n displays the line number. It becomes useful when you need to resume the file in less, compare two searches, or copy the excerpt into a ticket. The quotes prevent the shell from interpreting special characters in the pattern. The grep manual details the search and context options.
-isearches case-insensitively.-nadds the line number.-Ftreats the text as a literal string, useful for an error containing.,[or?.-Eenables extended regular expressions.-C 3displays three lines before and after each match.
For an exact error, prefer -F. An IP address, a path, or a message with brackets can otherwise be interpreted as a regular expression:
grep -n -F 'connection refused [127.0.0.1:5432]' /var/log/my-service.log
Keep the lines that explain the error
A line marked ERROR rarely indicates the cause by itself. Display the context before concluding:
grep -n -i -C 3 'error' /var/log/my-service.log
grep -n -i -A 5 'failed' /var/log/my-service.log
grep -n -i -B 5 'panic' /var/log/my-service.log
-C 3 keeps three lines on each side. -A only displays the following lines, -B only the preceding ones. If multiple errors are far apart, grep separates the groups with --. This separator is not part of the log.
When you know several symptoms, combine them with -E:
grep -n -i -E 'error|failed|timeout|refused' /var/log/my-service.log
This command also returns messages that do not necessarily concern your incident. Then add the process name, the port, or the request ID rather than arbitrarily lengthening the list of keywords.
Filter journalctl before passing grep
With systemd, start by limiting the log to the unit and the period of the incident. You avoid mixing messages from other services:
journalctl -u nginx --since '30 minutes ago' --no-pager
journalctl -u nginx --since '30 minutes ago' --no-pager | grep -n -i -C 2 'error'
Replace nginx with the actual name of the unit, such as postgresql, docker, or your application service. If the incident follows a restart, add -b to stay on the current boot. The journalctl manual also describes filters by unit and by period. Our guide on journalctl and the logs from the last boot details this filter.
Do not launch a search over years of logs before framing the time of the problem. An error seen at 2:12 PM deserves a short window around 2:12 PM, and then a broader read if no cause appears.
Follow the service during reproduction
For a reproducible problem, open a second terminal and watch only the new lines:
journalctl -fu nginx
tail -F /var/log/nginx/error.log | grep --line-buffered -i -E 'error|warn|failed'
journalctl -f follows the log live. tail -F also continues after a file rotation, which is safer than tail -f on many application logs. The --line-buffered option keeps the output readable after piping to grep.
Then trigger the failing action only once: an HTTP request, a controlled restart, or a test connection. If you run multiple tests at once, you will no longer know which line belongs to which attempt. To follow a classic file, you can also check our method with tail.
When you find an error, note the time, the unit or the affected process, then the lines around the message. This is more useful than a copy-paste of a thousand lines of logs, and it avoids modifying a configuration before identifying the faulty service.
n