Streams

When defining a stream, you should use a command that follows new writes on logs and print them as they arise.

The command should not print older lines. For example, tail -f /var/log/nginx/access.log will print the last 10 lines first, then follow appended lines. This a problem because restarting reaction will result in the same 10 logs potentially printed multiple times.

Examples of good commands:

Plain file

Follow logs of one file

tail -fn0 <FILE>

Follow multiple files as one stream. It will print some extra lines. Check them and see if they will match your regexes.

tail -fn0 <FILE1> <FILE2>

Follow multiple files as one stream. This alternative pattern can work for any command. sh will launch multiple commands in background, then until all of them exit.

sh -c 'tail -fn0 <FILE1> & tail -fn0 <FILE2> & wait'

⚠️ tail -f and logrotate

When files are rotated, tail -f may stay on the rotated file and miss new inputs.

Using tail -F instead permits to listen on a specific path, even if the actual file under it changes. See its manual for more details.

SystemD / JournalD

Logs of one systemd unit

journalctl -fn0 -u <UNIT>

Logs of multiple systemd units

journalctl -fn0 -u <UNIT> -u <UNIT>

Docker

Logs of one container

docker logs -fn0 <CONTAINER>

Logs of all the services of a docker compose file

docker compose --project-directory /path/to/directory logs -fn0

⚠️ docker logs print program's stderr to stderr as well, and reaction only reads stdout. So we might need to capture stdout and stderr depending on how your container does log:

cmd: ['sh', '-c', 'exec docker logs -fn0 <container> 2>&1']

There is virtually no overhead, as the sh process replaces itself with the docker logs command.

In reaction v2, stderr is read as well, so this trick is no longer needed.