Important: This documentation is about an older version. It's relevant only to the release noted, many of the features and functions have been updated or replaced. Please view the current version.
Promtail and Log Rotation
Why does log rotation matter?
At any point in time, there may be three processes working on a log file as shown in the image below.
- Appender - A writer that keeps appending to a log file. This can be your application or some system daemons like Syslog, Docker log driver or Kubelet, etc.
- Tailer - A reader that reads log lines as they are appended, for example, agents like Promtail.
- Log Rotator - A process that rotates the log file either based on time (for example, scheduled every day) or size (for example, a log file reached its maximum size).
NOTE: Here
fd
defines a file descriptor. Once a file is open for read or write, The Operating System returns a unique file descriptor (usually an integer) per process, and all the operations like read and write are done over that file descriptor. In other words, once the file is opened successfully, the file descriptor matters more than the file name.
One of the critical components here is the log rotator. Let’s understand how it impacts other components like the appender and tailer.
In general, when a software program rotates a log, it can be done in two ways internally.
Given a log file named error.log
- Copy the log file with a different name, for example,
error.log.1
and truncate the original log fileerror.log
. - Rename the log file with a different name, for example,
error.log.1
and create a new log file with the original nameerror.log
.
In both cases, after log rotation, all new log lines are written to the original error.log
file.
These two methods of log rotation are shown in the following images.
Copy and Truncate
Rename and Create
Both types of log rotation produce the same result. However, there are some subtle differences.
Copy and Truncate(1) favors the appender
as its descriptor for the original log file error.log
doesn’t change. Therefore, it can keep writing to the same file descriptor. In other words, re-opening the file is not needed.
However, (1) has a serious problem when considering the tailer
. There is a race between truncating the file and the tailer
finishing reading that log file. Meaning, there is a high chance of the log rotation mechanism truncating the file error.log
before the tailer
reads everything from it.
This is where Rename and Create(2) can help. Here, when the log file error.log
is renamed to error.log.1
, the tailer
still holds the file descriptor of error.log.1
. Therefore, it can continue reading the log file until it is completed. But that comes with the tradeoff: with (2), you have to signal the appender
to reopen error.log
(and appender
should be able to reopen it). Otherwise, it would keep writing to error.log.1
as the file descriptor won’t change. The good news is that most of the popular appender
solutions (for example, Syslog, Kubelet, Docker log driver) support reopening log files when they are renamed.
We recommend Rename and Create(2) as that is the method which works well with Promtail (or any similar log scraping agent) without any data loss. Now let’s understand exactly how we configure log rotation in different platforms.
Configure log rotation
Your logs can be rotated by different components depending on where you are running your applications or services. If you are running them on Linux machines, there is a high chance you are using the logrotate
utility. However, if you are running in Kubernetes, it’s not that obvious what rotates the logs and interestingly it may depend on what container runtime your Kubernetes cluster is using.
Non-Kubernetes
As mentioned above, in Linux machines, log rotation is often handled by the logrotate
utility.
The configuration for logrotate
is usually located in /etc/logrotate/
.
It has a wide range of options for compression, mailing, running scripts pre- and post-rotation, etc.
It supports both methods of log rotation described previously.
Copy and Truncate
/var/log/apache2/*.log {
weekly
maxsize 1G
copytruncate
}
Here copytruncate
mode works exactly like (1) explained above.
Rename and Create (Recommend)
/var/log/apache2/*.log {
weekly
maxsize 1G
create
}
Here, the create
mode works as explained in (2) above. The create
mode is optional because it’s the default mode in logrotate
.
Kubernetes
Kubernetes Service Discovery in Promtail also uses file-based scraping. Meaning, logs from your pods are stored on the nodes and Promtail scrapes the pod logs from the node files.
You can configure the kubelet
process running on each node to manage log rotation via two configuration settings.
containerLogMaxSize
- It defines the maximum size of the container log file before it is rotated. For example: “5Mi” or “256Ki”. Default: “10Mi”.containerLogMaxFiles
- It specifies the maximum number of container log files that can be present per container. Default: 5
Both should be part of the kubelet
config. If you run a managed version of Kubernetes in Cloud, refer to your cloud provider documentation for configuring kubelet
. Examples GKE, AKS and EKS.
NOTE: Log rotation managed by
kubelet
supports only rename + create and doesn’t support copy + truncate.
If kubelet
is not configured to manage the log rotation, then it’s up to the Container Runtime Interface (CRI) the cluster uses. Alternatively, log rotation can be managed by the logrotate
utility in the Kubernetes node itself.
Check your container runtime (CRI) on your nodes by running:
$ kubectl get nodes -o wide
Two of the commonly used CRI implementations are containerd
and docker
.
containerd CRI
At the time of writing this guide, containerd
doesn’t support any method of log rotation. In this case, rotation is often handled by kubelet
itself. Managed Kubernetes clusters like GKE and AKS use containerd
as runtime and log rotation is handled by kubelet
. EKS after version 1.24 also uses containerd
as its default container runtime.
docker CRI
When using docker
as runtime (EKS before 1.24 uses it by default), log rotation is managed by its logging driver (if supported). Docker has support for several logging drivers.
You can determine which logging driver docker
is using by running the following command:
docker info --format '{{.LoggingDriver}}'
Out of all these logging drivers only the local
(default) and the json-file
drivers support log rotation. You can configure the following log-opts
under /etc/docker/daemon.json
max-size
- The maximum size of the log file before it is rotated. A positive integer plus a modifier representing the unit of measure (k, m, or g). Defaults to20m
(20 megabytes).max-file
- The maximum number of log files that can be present. If rolling the logs creates excess files, the oldest file is removed. A positive integer. Defaults to 5.
Example /etc/docker/daemon.json
:
{
"log-driver": "local",
"log-opts": {
"max-size": "10m",
"max-file": "10"
}
}
If neither kubelet
nor CRI
is configured for rotating logs, then the logrotate
utility can be used on the Kubernetes nodes as explained previously.
NOTE: We recommend using kubelet for log rotation.
Configure Promtail
Promtail uses polling
to watch for file changes. A polling
mechanism combined with a copy and truncate log rotation may result in losing some logs. As explained earlier in this topic, this happens when the file is truncated before Promtail reads all the log lines from such a file.
Therefore, for a long-term solution, we strongly recommend changing the log rotation strategy to rename and create. Alternatively, as a workaround in the short term, you can tweak the promtail client’s batchsize
config to set higher values (like 5M or 8M). This gives Promtail more room to read loglines without frequently waiting for push responses from the Loki server.