← All posts

How to tail a remote log file from your Mac without a terminal

The quickest way to tail a remote log file is one command: ssh user@host tail -F /path/to/file.log. It streams new lines to your Terminal until you press Control-C. That works when you have a shell on the server. When you do not (SFTP-only accounts, hardened servers, colleagues who would rather not live in a terminal), you can still follow a log by repeatedly reading the end of the file over SFTP, which is what a graphical log tail does.

Here are both approaches, and the details that trip each of them up.

Tailing a remote log file over SSH

ssh deploy@example.com 'tail -F -n 100 /var/log/nginx/error.log'

-n 100 shows the last hundred lines first. The capital -F matters. Lowercase -f follows the open file, so when logrotate renames error.log to error.log.1 and creates a new one, tail -f keeps watching the old renamed file and goes quiet. -F follows the name and reopens it when it is replaced. The tail manual calls this --follow=name --retry.

To see only the lines you care about, filter on the server so less data crosses the network. --line-buffered stops grep holding output back in a buffer:

ssh deploy@example.com 'tail -F /var/log/app/app.log | grep --line-buffered -i error'

Services that log to the systemd journal rather than a file need journalctl instead:

ssh deploy@example.com 'journalctl -f -u myapp'

And if you want to scroll back while following, less +F follows a file like tail -f; press Control-C to stop following and browse, then F to resume.

Why it is not always that simple

No shell

Many servers give deployment accounts SFTP and nothing else, using ForceCommand internal-sftp in sshd_config. The ssh ... tail command simply fails, because there is no shell to run it. These are often exactly the servers whose logs you most need to read.

Permissions

System logs are rarely world-readable. On Debian and Ubuntu, for example, nginx logs belong to the adm group with mode 640. Rather than reading them as root, add your account to that group:

sudo usermod -aG adm deploy

The change applies from your next login.

Rotation

Logrotate works in one of two ways. With create, which most distribution configurations use, it renames the file and makes a new empty one. With copytruncate it copies the contents away and truncates the original to zero bytes. Any tool following a log has to notice both: the file at the path being replaced, and the file it is reading suddenly becoming shorter.

Many logs, many servers

Following an access log, an error log and an application log across two servers means five Terminal tabs, each with its own SSH session, and some way to tell them apart.

How tailing over SFTP works

SFTP has no "notify me when this file grows" command, but it has everything needed to fake one:

  1. Ask for the file's size with a stat.
  2. If it is larger than last time, open it and read from the previous offset to the end.
  3. If it is smaller than last time, it was truncated or rotated, so start again from the beginning.
  4. Wait a moment and repeat.

A well-behaved implementation also holds back a partial last line until the rest of it arrives, and avoids splitting a multi-byte UTF-8 character across two reads. The cost is a short delay, one poll interval, and a single stat request per interval when nothing has changed. The approach works on SFTP-only accounts, and over FTP and FTPS too, because it needs nothing beyond reading a file.

Following a log in Wharf

Wharf builds this in. Right-click any file in the remote pane and choose Follow Log…. The log opens in its own window, named after the file and the site, so you can keep it beside your editor or open several at once for different servers.

A log window uses its own connection, so following a busy log does not take a slot away from your transfers. It works over SFTP, FTP and FTPS, including through a jump host for SFTP sites. The features overview shows it alongside the rest of Wharf.

Limits worth knowing

For a related way of working with files in place, see editing remote files in your own editor.