Docker: How to clear the logs properly for a Docker container?

DockerDocker ComposeBoot2dockerDocker Machine

Docker Problem Overview


I use docker logs [container-name] to see the logs of a specific container.

Is there an elegant way to clear these logs?

Docker Solutions


Solution 1 - Docker

First the bad answer. From this question there's a one-liner that you can run:

echo "" > $(docker inspect --format='{{.LogPath}}' <container_name_or_id>)

instead of echo, there's the simpler:

: > $(docker inspect --format='{{.LogPath}}' <container_name_or_id>)

or there's the truncate command:

truncate -s 0 $(docker inspect --format='{{.LogPath}}' <container_name_or_id>)

I'm not a big fan of either of those since they modify Docker's files directly. The external log deletion could happen while docker is writing json formatted data to the file, resulting in a partial line, and breaking the ability to read any logs from the docker logs cli. For an example of that happening, see this comment on duketwo's answer:

> after emptying the logfile, I get this error: error from daemon in stream: Error grabbing logs: invalid character '\x00' looking for beginning of value

Instead, you can have Docker automatically rotate the logs for you. This is done with additional flags to dockerd if you are using the default JSON logging driver:

dockerd ... --log-opt max-size=10m --log-opt max-file=3

You can also set this as part of your daemon.json file instead of modifying your startup scripts:

{
  "log-driver": "json-file",
  "log-opts": {"max-size": "10m", "max-file": "3"}
}

These options need to be configured with root access. Make sure to run a systemctl reload docker after changing this file to have the settings applied. This setting will then be the default for any newly created containers. Note, existing containers need to be deleted and recreated to receive the new log limits.


Similar log options can be passed to individual containers to override these defaults, allowing you to save more or fewer logs on individual containers. From docker run this looks like:

docker run --log-driver json-file --log-opt max-size=10m --log-opt max-file=3 ...

or in a compose file:

version: '3.7'
services:
  app:
    image: ...
    logging:
      options:
        max-size: "10m"
        max-file: "3"

For additional space savings, you can switch from the json log driver to the "local" log driver. It takes the same max-size and max-file options, but instead of storing in json it uses a binary syntax that is faster and smaller. This allows you to store more logs in the same sized file. The daemon.json entry for that looks like:

{
  "log-driver": "local",
  "log-opts": {"max-size": "10m", "max-file": "3"}
}

The downside of the local driver is external log parsers/forwarders that depended on direct access to the json logs will no longer work. So if you use a tool like filebeat to send to Elastic, or Splunk's universal forwarder, I'd avoid the "local" driver.

I've got a bit more on this in my Tips and Tricks presentation.

Solution 2 - Docker

Use:

truncate -s 0 /var/lib/docker/containers/*/*-json.log

You may need sudo

sudo sh -c "truncate -s 0 /var/lib/docker/containers/*/*-json.log"

ref. Jeff S. https://stackoverflow.com/questions/42510002/how-to-clear-the-logs-properly-for-a-docker-container#comment86247471_43570083

Reference: https://stackoverflow.com/questions/980283/truncating-a-file-while-its-being-used-linux

Solution 3 - Docker

On Docker for Windows and Mac, and probably others too, it is possible to use the tail option. For example:

docker logs -f --tail 100

This way, only the last 100 lines are shown, and you don't have first to scroll through 1M lines...

(And thus, deleting the log is probably unnecessary)

Solution 4 - Docker

sudo sh -c "truncate -s 0 /var/lib/docker/containers/*/*-json.log"

Solution 5 - Docker

You can set up logrotate to clear the logs periodically.

Example file in /etc/logrotate.d/docker-logs

/var/lib/docker/containers/*/*.log {
 rotate 7
 daily
 compress
 size=50M
 missingok
 delaycompress
 copytruncate
}

Solution 6 - Docker

Docker4Mac, a 2018 solution:

LOGPATH=$(docker inspect --format='{{.LogPath}}' <container_name_or_id>)
docker run -it --rm --privileged --pid=host alpine:latest nsenter -t 1 -m -u -n -i -- truncate -s0 $LOGPATH

The first line gets the log file path, similar to the accepted answer.

The second line uses nsenter that allows you to run commands in the xhyve VM that servers as the host for all the docker containers under Docker4Mac. The command we run is the familiar truncate -s0 $LOGPATH from non-Mac answers.

If you're using docker-compose, the first line becomes:

local LOGPATH=$(docker inspect --format='{{.LogPath}}' $(docker-compose ps -q <service>))

and <service> is the service name from your docker-compose.yml file.

Thanks to https://github.com/justincormack/nsenter1 for the nsenter trick.

Solution 7 - Docker

You can also supply the log-opts parameters on the docker run command line, like this:

docker run --log-opt max-size=10m --log-opt max-file=5 my-app:latest

or in a docker-compose.yml like this

my-app:
image: my-app:latest
logging:
    driver: "json-file"
    options:
        max-size: "10m"
        max-file: "5"

Credits: https://medium.com/@Quigley_Ja/rotating-docker-logs-keeping-your-overlay-folder-small-40cfa2155412 (James Quigley)

Solution 8 - Docker

You can't do this directly through a Docker command.

You can either limit the log's size, or use a script to delete logs related to a container. You can find scripts examples here (read from the bottom): Feature: Ability to clear log history #1083

Check out the logging section of the docker-compose file reference, where you can specify options (such as log rotation and log size limit) for some logging drivers.

Solution 9 - Docker

As a root user, try to run the following:

>  /var/lib/docker/containers/*/*-json.log

or

cat /dev/null > /var/lib/docker/containers/*/*-json.log

or

echo "" > /var/lib/docker/containers/*/*-json.log

Solution 10 - Docker

Here is a cross platform solution to clearing docker container logs:

docker run --rm -v /var/lib/docker:/var/lib/docker alpine sh -c "echo '' > $(docker inspect --format='{{.LogPath}}' CONTAINER_NAME)"

Paste this into your terminal and change CONTAINER_NAME to desired container name or id.

Solution 11 - Docker

On my Ubuntu servers even as sudo I would get Cannot open ‘/var/lib/docker/containers/*/*-json.log’ for writing: No such file or directory

But combing the docker inspect and truncate answers worked :

sudo truncate -s 0 `docker inspect --format='{{.LogPath}}' <container>`

Solution 12 - Docker

I do prefer this one (from solutions above):

truncate -s 0 /var/lib/docker/containers/*/*-json.log

However I'm running several systems (Ubuntu 18.x Bionic for example), where this path does not work as expected. Docker is installed through Snap, so the path to containers is more like:

truncate -s 0 /var/snap/docker/common/var-lib-docker/containers/*/*-json.log

Solution 13 - Docker

Not sure if this is helpful for you, but removing the container always helps.

So, if you use docker-compose for your setup, you can simply use docker-compose down && docker-compose up -d instead of docker-compose restart. With a proper setup (make sure to use volume mounts for persistent data), you don't lose any data this way.

Sure, this is more than the OP requested. But there are various situations where the other answers cannot help (if using a remote docker server or working on a Windows machine, accessing the underlying filesystem is proprietary and difficult)

Solution 14 - Docker

Linux/Ubuntu:

If you have several containers and you want to remove just one log but not others.

  • (If you have issues like "Permission denied" do first sudo su.)
  • List all containers: docker ps -a
  • Look for the container you desire and copy the CONTAINER ID. Example: E1X2A3M4P5L6.
  • Containers folders and real names are longer than E1X2A3M4P5L6 but first 12 characters are those resulted in docker ps -a.
  • Remove just that log: > /var/lib/docker/containers/E1X2A3M4P5L6*/E1X2A3M4P5L6*-json.log (Replace E1X2A3M4P5L6 for your result !! )

As you can see, inside /containers are the containers, and logs has the same name but with -json.log at the end. You just need to know that first 12 characters, because * means "anything".

Solution 15 - Docker

Thanks to answer by @BMitch, I've just wrote a shell script to clean logs of all the containers:

#!/bin/bash
ids=$(docker ps -a --format='{{.ID}}')
for id in $ids
do
        echo $(docker ps -a --format='{{.ID}} ### {{.Names}} ### {{.Image}}' | fgrep $id)
        truncate -s 0 $(docker inspect --format='{{.LogPath}}' $id)
        ls -llh $(docker inspect --format='{{.LogPath}}' $id)
done

Solution 16 - Docker

Docker for Mac users, here is the solution:

    1. Find log file path by:

    $ docker inspect | grep log

    1. SSH into the docker machine( suppose the name is default, if not, run docker-machine ls to find out):

    $ docker-machine ssh default

    1. Change to root user(reference):

    $ sudo -i

    1. Delete the log file content:

    $ echo "" > log_file_path_from_step1

Solution 17 - Docker

I needed something I could run as one command, instead of having to write docker ps and copying over each Container ID and running the command multiple times. I've adapted BMitch's answer and thought I'd share in case someone else may find this useful.

Mixing xargs seems to pull off what I need here:

docker ps --format='{{.ID}}' | \
  xargs -I {} sh -c 'echo > $(docker inspect --format="{{.LogPath}}" {})'

This grabs each Container ID listed by docker ps (will erase your logs for any container on that list!), pipes it into xargs and then echoes a blank string to replace the log path of the container.

Solution 18 - Docker

To remove/clear docker container logs we can use below command >$(docker inspect container_id|grep "LogPath"|cut -d """ -f4) or >$(docker inspect container_name|grep "LogPath"|cut -d """ -f4)

Solution 19 - Docker

This will delete all logfiles for all containers:

sudo find /var/lib/docker/containers/ -type f -name "*.log" -delete

Solution 20 - Docker

If you need to store a backup of the log files before deleting them, I have created a script that performs the following actions (you have to run it with sudo) for a specified container:

  1. Creates a folder to store compressed log files as backup.
  2. Looks for the running container's id (specified by the container's name).
  3. Copy the container's log file to a new location (folder in step 1) using a random name.
  4. Compress the previous log file (to save space).
  5. Truncates the container's log file by certain size that you can define.

Notes:

  • It uses the shuf command. Make sure your linux distribution has it or change it to another bash-supported random generator.
  • Before use, change the variable CONTAINER_NAME to match your running container; it can be a partial name (doesn't have to be the exact matching name).
  • By default it truncates the log file to 10M (10 megabytes), but you can change this size by modifying the variable SIZE_TO_TRUNCATE.
  • It creates a folder in the path: /opt/your-container-name/logs, if you want to store the compressed logs somewhere else, just change the variable LOG_FOLDER.
  • Run some tests before running it in production.
#!/bin/bash
set -ex

############################# Main Variables Definition:
CONTAINER_NAME="your-container-name"
SIZE_TO_TRUNCATE="10M"

############################# Other Variables Definition:
CURRENT_DATE=$(date "+%d-%b-%Y-%H-%M-%S")
RANDOM_VALUE=$(shuf -i 1-1000000 -n 1)
LOG_FOLDER="/opt/${CONTAINER_NAME}/logs"
CN=$(docker ps --no-trunc -f name=${CONTAINER_NAME} | awk '{print $1}' | tail -n +2)
LOG_DOCKER_FILE="$(docker inspect --format='{{.LogPath}}' ${CN})"
LOG_FILE_NAME="${CURRENT_DATE}-${RANDOM_VALUE}"

############################# Procedure:
mkdir -p "${LOG_FOLDER}"
cp ${LOG_DOCKER_FILE} "${LOG_FOLDER}/${LOG_FILE_NAME}.log"
cd ${LOG_FOLDER}
tar -cvzf "${LOG_FILE_NAME}.tar.gz" "${LOG_FILE_NAME}.log"
rm -rf "${LOG_FILE_NAME}.log"
truncate -s ${SIZE_TO_TRUNCATE} ${LOG_DOCKER_FILE}

You can create a cronjob to run the previous script every month. First run:

sudo crontab -e

Type a in your keyboard to enter edit mode. Then add the following line:

0 0 1 * * /your-script-path/script.sh

Hit the escape key to exit Edit mode. Save the file by typing :wq and hitting enter. Make sure the script.sh file has execution permissions.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionYoussouf MaigaView Question on Stackoverflow
Solution 1 - DockerBMitchView Answer on Stackoverflow
Solution 2 - DockerduketwoView Answer on Stackoverflow
Solution 3 - DockerEgbert NieropView Answer on Stackoverflow
Solution 4 - DockerrichardView Answer on Stackoverflow
Solution 5 - DockerAlexPntView Answer on Stackoverflow
Solution 6 - DockerelifinerView Answer on Stackoverflow
Solution 7 - DockerDag BaardsenView Answer on Stackoverflow
Solution 8 - DockerTristanView Answer on Stackoverflow
Solution 9 - Dockermatson kepsonView Answer on Stackoverflow
Solution 10 - DockerMax BarrassView Answer on Stackoverflow
Solution 11 - DockeraqwanView Answer on Stackoverflow
Solution 12 - DockerigraczechView Answer on Stackoverflow
Solution 13 - DockerDaniel AlderView Answer on Stackoverflow
Solution 14 - DockerEmeeusView Answer on Stackoverflow
Solution 15 - DockerMohsen AbasiView Answer on Stackoverflow
Solution 16 - DockerJinsong LiView Answer on Stackoverflow
Solution 17 - DockerReeceView Answer on Stackoverflow
Solution 18 - Dockervivekanand singhView Answer on Stackoverflow
Solution 19 - DockerJakobovskiView Answer on Stackoverflow
Solution 20 - DockerEdenshawView Answer on Stackoverflow