Logging¶
Surfmeter Automator uses pino for structured JSON logging. Each measurement run produces log output that includes startup information, browser events, measurement progress, and results. Understanding how this output is captured depends on whether you run Automator natively or inside Docker.
Log Levels¶
You can control the verbosity of log output with the LOG_LEVEL environment variable. The available levels, from least to most verbose, are:
error– only errorswarning– errors and warningsinfo– the default; normal operational messagesdebug– additional diagnostic outputtrace– very detailed tracingextreme– maximum verbosity
Set the variable when running Automator directly:
Or add it to a schedule entry's env block in your automatorConfig.json:
{
"id": "STUDY_YOUTUBE",
"studyId": "STUDY_YOUTUBE",
"cronSchedule": "*/15 * * * *",
"env": {
"LOG_LEVEL": "debug"
}
}
You can also set it globally for all schedules via globalScheduleSettings.env:
Logging in Native Deployments¶
When Automator runs natively (outside Docker), scheduled measurements are executed by cron. By default, cron delivers command output via its mail transfer agent (MTA). On most systems this MTA is not configured, which means log output is silently discarded.
To persist the logs, set cronLogFile in your automatorConfig.json. You can set it per schedule entry or globally:
The $HOME and $TMP variables are expanded automatically. Make sure the target directory exists before loading the schedule:
When you run a study manually (not via cron), output goes to your terminal's stdout as usual.
The built-in limit is not log retention
Automator has a built-in size safeguard, but it clears the current file instead of retaining history. Set up logrotate if you need older logs.
Logging in Docker Deployments¶
Docker containers write their stdout and stderr to the Docker logging driver, which you can inspect with:
The Surfmeter Docker entrypoint produces its own structured JSON log lines for container lifecycle events (startup, registration, schedule loading, etc.).
Cron output forwarding¶
Cron jobs inside a container cannot write to container stdout directly, because cron runs as a separate process without access to PID 1's file descriptors. To solve this, the Docker entrypoint sets up a named pipe (FIFO) at the path defined by the SURFMETER_CRON_LOG environment variable (default: /tmp/surfmeter-cron.log). When a schedule entry does not specify a cronLogFile, Automator automatically redirects the cron job's output to this FIFO. The entrypoint reads from the pipe in the background and forwards lines to container stdout:
- JSON lines (pino output from Automator) are forwarded as-is
- Non-JSON lines are wrapped in the entrypoint's own JSON log format
This means that with the default Docker setup, all measurement logs appear in docker compose logs without any extra configuration.
Overriding with cronLogFile¶
If you set a cronLogFile in your automatorConfig.json, cron output is written to that file instead of the FIFO. This bypasses Docker's logging entirely for those schedule entries.
File-based logging in Docker bypasses Docker rotation
If you explicitly set cronLogFile to a file path inside the container (i.e. one that you have not mapped to a volume or bind mount), logs will not appear in docker compose logs and will not be managed by Docker's log rotation. Automator's built-in size safeguard still applies. Set up logrotate if you need to retain older logs.
If the path is not backed by a volume or bind mount, restarting the container loses the file.
Disabling the FIFO¶
To disable the FIFO forwarding entirely, set the environment variable to an empty string in your docker-compose.yml:
Be aware that without the FIFO and without a cronLogFile, cron output inside Docker is lost.
Built-in Cron Logfile Safeguard¶
Starting with Automator 1.63.1, every invocation checks all cronLogFile paths in the merged automatorConfig.json and automatorConfig.local.json. The check runs in the background, so it does not delay the requested action. When a regular file has reached 1024 MiB, Automator truncates it in place. Missing paths and non-regular files, including the Docker FIFO, are ignored.
Set SURFMETER_CRON_LOG_MAX_SIZE_MB to change the limit in MiB:
Set it to 0 to disable the safeguard. Invalid values produce a warning and retain the 1024 MiB default. The variable must be present in the environment of the scheduled Automator process; see Using Overrides with Scheduled Jobs for the available configuration methods.
Truncation clears the current file and retains no history. It is a last-resort disk-usage safeguard for systems without logrotate, not a replacement for rotation when you need historical logs.
Summary¶
| Setup | Default behavior | Where logs appear |
|---|---|---|
| Native, manual run | stdout | Terminal |
Native, cron, no cronLogFile |
Sent to cron MTA | Usually lost (MTA not configured) |
Native, cron, with cronLogFile |
Appended to file | The specified file |
Docker, no cronLogFile |
FIFO forwarding to container stdout | docker compose logs |
Docker, with cronLogFile |
Appended to file | The specified file (not in docker compose logs) |
Log Rotation¶
Use log rotation when you want to retain historical file logs. Automator's built-in safeguard only clears an oversized current file.
On Linux, the standard tool for this is logrotate. Create a configuration file, for example /etc/logrotate.d/surfmeter:
/home/surfmeter/logs/surfmeter-automator.log {
daily
rotate 14
compress
missingok
notifempty
copytruncate
}
This rotates the log daily, keeps 14 compressed copies, and uses copytruncate so that the running process does not need to be signaled. Adjust the path and retention to your needs.
Docker's built-in log rotation
When using the default FIFO-based forwarding (i.e., not setting cronLogFile), Docker manages log rotation through its logging driver. The default json-file driver supports the max-size and max-file options, which you can configure globally in /etc/docker/daemon.json:
Or per container in docker-compose.yml:
This is another advantage of letting logs flow through Docker's standard mechanism rather than redirecting to a file.