Linux tail Multiple Files: Real Examples and Techniques

tail multiple files in Linux simultaneously — using tail -f, multitail, and journalctl to monitor several log files at once in real production scenarios.

April 22, 2026·5 min read·Damon

Watching one log file is easy. The real challenge is correlating events across multiple files — application log, nginx error log, and system journal — at the same time.


TL;DR

# Basic: tail multiple files (alternates output, shows filename)
tail -f /var/log/nginx/error.log /var/log/app/app.log

# Merge all output with timestamps
tail -f /var/log/nginx/error.log /var/log/app/app.log | ts

# Split view (requires multitail)
multitail /var/log/nginx/error.log /var/log/app/app.log

# Combine systemd + flat file
{ journalctl -fu nginx & tail -F /var/log/app/app.log; }

tail -f with Multiple Files

The simplest approach — tail accepts multiple file arguments:

tail -f /var/log/nginx/access.log /var/log/nginx/error.log

Output:

==> /var/log/nginx/access.log <==
1.2.3.4 - - [22/Apr/2026:09:15:01] "GET /api/v1/users HTTP/1.1" 200 1234

==> /var/log/nginx/error.log <==
2026/04/22 09:15:02 [error] 1234#1234: *18423 connect() failed

==> /var/log/nginx/access.log <==
5.6.7.8 - - [22/Apr/2026:09:15:03] "POST /api/v1/login HTTP/1.1" 429 89

tail alternates between files, printing a header ==> filename <== whenever the source changes. The output is interleaved chronologically as new lines arrive.

With capital -F (follow across rotation)

tail -F /var/log/nginx/error.log /var/log/app/app.log
# -F reopens files by name when they're rotated
# Essential for long-running sessions

Merge Output Into One Stream

When you need a clean chronological stream without the file headers:

# Remove the "==> filename <==" headers
tail -f /var/log/nginx/error.log /var/log/app/app.log | grep -v "^==>"

# Add timestamps to each line
tail -f /var/log/nginx/error.log /var/log/app/app.log | ts '[%H:%M:%S]'
# (requires moreutils: apt install moreutils)

Label Each Line With Its Source

# Run each tail in background, prefix with filename
tail -F /var/log/nginx/error.log | sed 's/^/[nginx] /' &
tail -F /var/log/app/app.log | sed 's/^/[app]   /' &
wait

Output:

[nginx] 2026/04/22 09:15:02 [error] connect() failed
[app]   2026/04/22 09:15:02 ERROR: upstream connection timeout
[nginx] 2026/04/22 09:15:03 [error] upstream timed out

Much easier to follow during an incident than unlabeled interleaved output.


multitail: Split-Pane View

multitail divides the terminal into sections — one per log file:

# Install
apt install multitail    # Ubuntu
dnf install multitail    # RHEL

# Two files, split horizontally
multitail /var/log/nginx/error.log /var/log/app/app.log

# Three files
multitail /var/log/nginx/error.log /var/log/nginx/access.log /var/log/app/app.log

# With color labels
multitail \
  -ci red    /var/log/nginx/error.log \
  -ci green  /var/log/nginx/access.log \
  -ci yellow /var/log/app/app.log

# Split vertically (-s flag)
multitail -s 2 /var/log/nginx/error.log /var/log/app/app.log

Keyboard shortcuts inside multitail:

  • b — scroll back in a pane
  • q — quit
  • a — add another file
  • / — search/filter

Mix systemd Journal + Flat Files

Many applications log to both systemd journal (via stdout) and flat files (via the app's logger). Watch both:

# Run both in parallel, output to same terminal
{
  journalctl -fu nginx --no-hostname
  &
  tail -F /var/log/app/app.log
} | grep -v "^$"

Or with labeling:

journalctl -fu nginx --no-hostname | sed 's/^/[systemd] /' &
tail -F /var/log/app/app.log | sed 's/^/[applog]  /' &
wait

Real Examples

Monitor a deployment across services

# Watch nginx + app + systemd journal during a deploy
multitail \
  -ci red    /var/log/nginx/error.log \
  -ci yellow /var/log/app/app.log \
  -j         # also include journal

# Or as background processes
tail -F /var/log/nginx/error.log | sed 's/^/NGINX: /' &
tail -F /var/log/app/app.log | sed 's/^/APP:   /' &
journalctl -fu myapp | sed 's/^/SRVD:  /' &
echo "Watching logs... Ctrl+C to stop"
wait

Watch access + error log, filter to 5xx only

tail -F /var/log/nginx/access.log /var/log/nginx/error.log | \
  grep --line-buffered -E "\" [5][0-9][0-9] |error|upstream"

Correlate app errors with nginx upstream failures

# Timestamped output, errors only
tail -F /var/log/nginx/error.log /var/log/app/app.log | \
  grep --line-buffered -iE "error|exception|fail" | \
  ts '[%Y-%m-%d %H:%M:%.S]'

Save incident logs while watching

tail -F /var/log/nginx/error.log /var/log/app/app.log | \
  tee /tmp/incident_$(date +%Y%m%d_%H%M%S).log

tail Wildcards

# All log files in a directory
tail -F /var/log/nginx/*.log

# All rotated logs too
tail -F /var/log/nginx/error.log*

# All application logs
tail -F /var/log/myapp/*.log

Common Mistakes

Mistake 1: Using -f instead of -F for long sessions -f (lowercase) follows the file descriptor. When a log rotates, the old descriptor is gone and tail stops receiving output. -F (uppercase) follows by filename and reopens when the file changes.

Mistake 2: Output getting cluttered with "==> filename <==" headers When multiple files update rapidly, the headers make output hard to read:

# Remove headers
tail -F /var/log/nginx/error.log /var/log/app/app.log | grep -v "^==>"

# Or use sed to add label instead
tail -F /var/log/nginx/error.log | sed 's/^/NGINX: /' &
tail -F /var/log/app/app.log | sed 's/^/APP:   /' &

Mistake 3: Missing buffered output in pipelines Piping tail -f through grep or awk can cause buffering — lines appear in bursts instead of as they arrive:

# Fix: add --line-buffered to grep
tail -F /var/log/app.log | grep --line-buffered "ERROR"

# Fix: unbuffer with stdbuf
tail -F /var/log/app.log | stdbuf -oL grep "ERROR"

Pro Tips

# Follow all .log files added to a directory in real time
# (requires inotifywait from inotify-tools)
inotifywait -m -e create /var/log/nginx/ --format "%f" | \
  while read file; do tail -F "/var/log/nginx/$file" & done

# Merge multiple files and add source label in one line
for f in /var/log/nginx/error.log /var/log/app/app.log; do
  tail -F "$f" | sed "s|^|$(basename $f): |" &
done
wait

# Kill all background tail processes when done
trap "kill 0" EXIT

Conclusion

tail -F file1 file2 is the quickest way to watch multiple files. The -F flag handles log rotation — always use it instead of -f for production sessions. For labeled output, pipe each tail into sed 's/^/[label] /' and run in the background. For split-pane visual monitoring, multitail is significantly easier to navigate during a real incident.


Related: How to Monitor Real-Time Logs in Linux — broader real-time log monitoring including journalctl filtering. Linux Log Analysis: Debug Issues Like a Senior Engineer — once the incident is over, how to analyze what happened.