Promtail
Promtail⚑
Promtail is an agent which ships the contents of local logs to a Loki instance.
It is usually deployed to every machine that runs applications which need to be monitored.
It primarily:
Discovers targets
Attaches labels to log streams
Pushes them to the Loki instance.
Installation⚑
Use patrickjahns ansible role. Some interesting variables are:
loki_url: localhost
promtail_system_user: root
promtail_config_clients:
- url: "http://{{ loki_url }}:3100/loki/api/v1/push"
external_labels:
hostname: "{{ ansible_hostname }}"
Configuration⚑
Promtail is configured in a YAML file (usually referred to as config.yaml) which contains information on the Promtail server, where positions are stored, and how to scrape logs from files.
To see the configuration that is being loaded at promtail use one of the next flags:
-
-print-config-stderr
is nice when running Promtail directly e.g. ./promtail as you can get a quick output of the entire Promtail config. -
-log-config-reverse-order
is the flag we run Promtail with in all our environments, the config entries are reversed so that the order of configs reads correctly top to bottom when viewed in Grafana’s Explore.
You can start from this basic configuration
wget https://raw.githubusercontent.com/grafana/loki/v2.9.1/clients/cmd/promtail/promtail-docker-config.yaml -O /data/promtail/promtail-config.yaml
Scraping configs⚑
Promtail borrows the same service discovery mechanism from Prometheus. promtail
is configured using a scrape_configs
stanza. relabel_configs
allows for fine-grained control of what to ingest, what to drop, and the final metadata to attach to the log line.
Once Promtail has a set of targets (i.e., things to read from, like files) and all labels are set correctly, it will start tailing (continuously reading) the logs from targets. Once enough data is read into memory or after a configurable timeout, it is flushed as a single batch to Loki.
As Promtail reads data from sources (files and systemd journal, if configured), it will track the last offset it read in a positions file. By default, the positions file is stored at /var/log/positions.yaml
. The positions file helps Promtail continue reading from where it left off in the case of the Promtail instance restarting.
The file target discovery⚑
Promtail discovers locations of log files and extract labels from them through the scrape_configs
section in the config YAML.
If you're going to use journald
for your logs you can skip this section.
scrape_configs:
- job_name: system
static_configs:
- targets:
- localhost
labels:
job: varlogs
__path__: /var/log/*log
Scrape journald logs⚑
On systems with systemd
, Promtail also supports reading from the journal. Unlike file scraping which is defined in the static_configs
stanza, journal scraping is defined in a journal
stanza:
scrape_configs:
- job_name: journal
journal:
json: false
max_age: 12h
path: /var/log/journal
labels:
job: systemd-journal
relabel_configs:
- source_labels: ['__journal__systemd_unit']
target_label: unit
- source_labels: ['__journal__hostname']
target_label: hostname
- source_labels: ['__journal_syslog_identifier']
target_label: syslog_identifier
- source_labels: ['__journal_transport']
target_label: transport
- source_labels: ['__journal_priority_keyword']
target_label: keyword
All fields defined in the journal section are optional, and are just provided here for reference.
max_age
ensures that no older entry than the time specified will be sent to Loki; this circumventsentry too old
errors.path
tells Promtail where to read journal entries from.labels
map defines a constant list of labels to add to every journal entry that Promtail reads.matches
field adds journal filters. If multiple filters are specified matching different fields, the log entries are filtered by both, if two filters apply to the same field, then they are automatically matched as alternatives.- When the
json
field is set to true, messages from the journal will be passed through the pipeline as JSON, keeping all of the original fields from the journal entry. This is useful when you don’t want to index some fields but you still want to know what values they contained. - When Promtail reads from the journal, it brings in all fields prefixed with
__journal_
as internal labels. Like in the example above, the_SYSTEMD_UNIT
field from the journal was transformed into a label calledunit
throughrelabel_configs
. Keep in mind that labels prefixed with__
will be dropped, so relabeling is required to keep these labels. Look at the systemd man pages for a list of fields exposed by the journal.
By default, Promtail reads from the journal by looking in the /var/log/journal
and /run/log/journal
paths. If running Promtail inside of a Docker container, the path appropriate to your distribution should be bind mounted inside of Promtail along with binding /etc/machine-id
. Bind mounting /etc/machine-id
to the path of the same name is required for the journal reader to know which specific journal to read from.
docker run \
-v /var/log/journal/:/var/log/journal/ \
-v /run/log/journal/:/run/log/journal/ \
-v /etc/machine-id:/etc/machine-id \
grafana/promtail:latest \
-config.file=/path/to/config/file.yaml
Scrape docker logs⚑
Docker service discovery allows retrieving targets from a Docker daemon. It will only watch containers of the Docker daemon referenced with the host parameter. Docker service discovery should run on each node in a distributed setup. The containers must run with either the json-file
or journald
logging driver.
Note that the discovery will not pick up finished containers. That means Promtail will not scrape the remaining logs from finished containers after a restart.
scrape_configs:
- job_name: docker
docker_sd_configs:
- host: unix:///var/run/docker.sock
refresh_interval: 5s
relabel_configs:
- source_labels: ['__meta_docker_container_name']
regex: '/(.*)'
target_label: 'container'
pipeline_stages:
- static_labels:
job: docker
__meta_docker_container_id
: the ID of the container__meta_docker_container_name
: the name of the container__meta_docker_container_network_mode
: the network mode of the container__meta_docker_container_label_<labelname>
: each label of the container__meta_docker_container_log_stream
: the log stream type stdout or stderr__meta_docker_network_id
: the ID of the network__meta_docker_network_name
: the name of the network__meta_docker_network_ingress
: whether the network is ingress__meta_docker_network_internal
: whether the network is internal__meta_docker_network_label_<labelname>
: each label of the network__meta_docker_network_scope
: the scope of the network__meta_docker_network_ip
: the IP of the container in this network__meta_docker_port_private
: the port on the container__meta_docker_port_public
: the external port if a port-mapping exists__meta_docker_port_public_ip
: the public IP if a port-mapping exists
If you've set some systemd services that run docker-compose it's a good idea not to ingest them with promtail so as not to have duplicate log lines:
scrape_configs:
- job_name: journal
journal:
json: false
max_age: 12h
path: /var/log/journal
labels:
job: systemd-journal
relabel_configs:
- source_labels: ['__journal__systemd_unit']
target_label: unit
- source_labels: ['__journal__hostname']
target_label: hostname
- source_labels: ['__journal_syslog_identifier']
target_label: syslog_identifier
- source_labels: ['__journal_transport']
target_label: transport
- source_labels: ['__journal_priority_keyword']
target_label: level
pipeline_stages:
- drop:
source: syslog_identifier
value: docker-compose
Fetch only some docker logs⚑
The labels can be used during relabeling. For instance, the following configuration scrapes the container named flog
and removes the leading slash (/) from the container name. yaml
scrape_configs:
- job_name: flog_scrape
docker_sd_configs:
- host: unix:///var/run/docker.sock
refresh_interval: 5s
filters:
- name: name
values: [flog]
relabel_configs:
- source_labels: ['__meta_docker_container_name']
regex: '/(.*)'
target_label: 'container'
Set the hostname label on all logs⚑
There are many ways to do it:
- Setting the label in the promtail launch command
bash sudo ./promtail-linux-amd64 --client.url=http://xxxx:3100/loki/api/v1/push --client.external-labels=hostname=$(hostname) --config.file=./config.yaml
This won't work if you're using promtail within a docker-compose because you can't use bash expansion in the docker-compose.yaml
file - Allowing env expansion and setting it in the promtail conf. You can launch the promtail command with -config.expand-env
and then set in each scrape jobs:
labels:
host: ${HOSTNAME}
promtail
within a docker as it will give you the ID of the docker - Set it in the promtail_config_clients
field as external_labels
of each promtail config: promtail_config_clients:
- url: "http://{{ loki_url }}:3100/loki/api/v1/push"
external_labels:
hostname: "{{ ansible_hostname }}"
labels:
host: {{ ansible_hostname }}
Monitorization⚑
Promtail exposes prometheus metrics on port 80 under the /metrics
endpoint if you're using docker or 9080 if you're using the program directly. The most interesting metrics are:
promtail_read_bytes_total
(Gauge): Number of bytes read.promtail_read_lines_total
(Counter): Number of lines read.promtail_dropped_bytes_total
(Counter): Number of bytes dropped because failed to be sent to the ingester after all retries.promtail_dropped_entries_total
(Counter): Number of log entries dropped because failed to be sent to the ingester after all retries.promtail_encoded_bytes_total
(Counter): Number of bytes encoded and ready to send.promtail_file_bytes_total
(Gauge): Number of bytes read from files.promtail_files_active_total
(Gauge): Number of active files.promtail_request_duration_seconds
(Histogram): Number of send requests.promtail_sent_bytes_total
(Counter): Number of bytes sent.promtail_sent_entries_total
(Counter): Number of log entries sent to the ingester.promtail_targets_active_total
(Gauge): Number of total active targets.promtail_targets_failed_total
(Counter): Number of total failed targets.
Once you add the target on prometheus you'll be able to monitor if the service is down. Other alerts can be:
Monitor errors when sending logs⚑
You can monitor this either through loki or prometheus. I feel that using loki may give you more insights. Then you can monitor it either on the promtail logs or the loki logs. After checking the traces on both sides I feel that the labels of the promtail one are cleaner.
Pipeline building⚑
In this issue there are nice examples on different pipelines.
Drop logs⚑
If you don't want the logs that have the keyword systemd-journal
and value docker-compose
you can add the next pipeline stage:
pipeline_stages:
- drop:
source: syslog_identifier
value: docker-compose
Basic concepts⚑
API⚑
Promtail features an embedded web server exposing a web console at /
and the following API endpoints:
- GET
/ready
: This endpoint returns 200 when Promtail is up and running, and there’s at least one working target. - GET
/metrics
: This endpoint returns Promtail metrics for Prometheus.
Troubleshooting⚑
Find where is the positions.yaml
file and see if it evolves.
Sometimes if you are not seeing the logs in loki it's because the query you're running is not correct.