15.1.2 Log Drivers
A focused guide to Log Drivers, connecting core concepts with practical Docker and container operations.
Log drivers are the pluggable backend implementations behind Docker's logging system, and understanding them as a plugin architecture, rather than just a list of configuration string values, clarifies why some drivers support reading logs back through docker logs while others do not, and how third-party or custom drivers can extend the system beyond what ships with Docker by default.
The driver as a plugin interface
Every logging driver implements the same basic contract: receive a stream of log messages from a container and do something with them. What differs between drivers is entirely what happens after that point, write to a local file, forward over the network, hand off to a system logging facility, and whether the driver also implements the read-back interface that docker logs depends on:
docker info --format '{{.Plugins.Log}}'
This command lists every logging driver currently available to the daemon, which includes the drivers built into Docker itself as well as any third-party logging plugins that have been installed separately.
Read-capable versus write-only drivers
Not every driver supports being queried back through docker logs; this is a specific capability a driver implementation may or may not provide, independent of whether it successfully captures and forwards log output:
docker logs my-api
Error response from daemon: configured logging driver does not support reading
json-file, local, and journald support reading; drivers like syslog, gelf, fluentd, and awslogs generally do not, since they hand log messages off to an external system and do not retain a locally queryable copy themselves. This is a direct, practical consequence of choosing a driver, not a bug, and should factor into the decision: a driver that cannot be queried locally requires the remote destination's own tooling for any kind of "tail the recent logs of this container" workflow.
Installing third-party logging driver plugins
Beyond the drivers built into Docker itself, the plugin system supports installing additional logging drivers distributed as Docker plugins, extending the daemon's logging capability to destinations not natively supported:
docker plugin install loki/docker-loki-logging-driver
{
"log-driver": "loki",
"log-opts": {
"loki-url": "http://loki-host:3100/loki/api/v1/push"
}
}
Once installed, a plugin-provided driver is referenced exactly the same way as a built-in one, through the --log-driver flag or the daemon's default configuration, which is what makes the plugin architecture practically transparent to anyone configuring a container's logging behavior.
Dual logging
Docker supports retaining a local, readable copy of logs even when a different primary driver is configured, through a dual logging mode, which addresses the read-capability gap of write-only drivers without giving up the benefits of forwarding to a remote destination:
{
"log-driver": "fluentd",
"log-opts": {
"fluentd-address": "fluentd-host:24224"
}
}
DOCKER_LOG_LEVEL=debug dockerd --log-driver=fluentd
When dual logging is active, the daemon caches log output locally in addition to forwarding it through the configured driver, allowing docker logs to continue functioning even though the primary destination is a non-read-capable driver, at the cost of the additional local disk and memory required to maintain that cache.
Driver-specific options and their inconsistency
Each driver supports its own distinct set of --log-opt key-value options, and there is no shared, universal option set across all drivers beyond a handful of common ones like max-size for the drivers that support local rotation:
docker run -d --log-driver=fluentd --log-opt fluentd-address=fluentd-host:24224 --log-opt tag="docker.{{.Name}}" my-api
docker run -d --log-driver=awslogs --log-opt awslogs-group=my-logs --log-opt awslogs-create-group=true my-api
Switching between drivers therefore typically requires reviewing that specific driver's documented options rather than assuming configuration translates directly from one driver to another; an option valid for one driver may be silently ignored or cause an outright error under a different one.
Verifying which driver and options are actually active
Because logging configuration can be set at the daemon level, overridden per Compose service, or overridden again per individual container run, confirming what is actually active for a specific running container is worth doing directly rather than assuming based on configuration files alone:
docker inspect my-api --format '{{json .HostConfig.LogConfig}}'
This reflects the actual, effective logging configuration for that specific container, accounting for any layering of daemon defaults and explicit overrides that occurred between the daemon's configuration and the container's own creation.
Writing a custom logging driver
For genuinely unsupported destinations, Docker's logging driver plugin API allows implementing an entirely custom driver, though this is a meaningfully more involved undertaking than configuring an existing one, requiring building and distributing a plugin that implements Docker's plugin protocol:
docker plugin create my-custom-log-driver ./plugin-rootfs
docker plugin enable my-custom-log-driver
This path is uncommon in practice, since the existing set of built-in and community-maintained third-party drivers already covers the large majority of destinations a typical deployment would need, and building a custom plugin is generally only justified when integrating with a genuinely proprietary or unusual logging backend with no existing driver.
Common mistakes
- Choosing a write-only driver without realizing
docker logswill stop working for that container, then being unable to quickly inspect recent output during an incident. - Assuming
--log-optkeys are portable across different drivers, leading to silently ignored or rejected options after switching drivers. - Not enabling dual logging when a write-only remote driver is required but local read access would still be valuable during routine debugging.
- Forgetting that logging configuration can be layered across daemon defaults, Compose overrides, and individual
docker runflags, and not verifying the actual effective configuration withdocker inspect. - Building a custom logging driver plugin before thoroughly checking whether an existing built-in or community driver already supports the intended destination.
Understanding log drivers as a plugin interface, rather than a fixed list of configuration strings, explains why some drivers support local reading and others do not, makes dual logging a sensible solution when both remote delivery and local readability are needed, and clarifies that the plugin system can be extended to genuinely novel destinations when the existing driver catalog does not already cover them.