Skip to content

nginx metrics and log collection with grafana, prometheus, loki

Published: at 04:45 PM

meta

Grafana - is the front-end dashboard website, that supports querying datasources, and displaying visualizatoins of the data. It is basically a full-stack webapp that you can self-host.

Prometheus - is a metrics collection endpoint. It runs as an http server that also “scrapes” target services, periodically via http. It becomes the primary data source for counters/timeseries when using grafana dashboards. Conceptually, it is the main database for recording and facilitating queries against the metrics.

Nginx Node exporter - it’s a confusing name, but in order for prometheus to scrape any useful data, it needs to be available to scrape on the target. The “node exporter” is what makes metrics data available for prometheus to scrape. There are many node exporters available for popular software services, including nginx.

Loki - is like prometheus, but for text logs. I.e., it receives a stream of text, generally the recent lines of a log file. The encoding and format of each line can be arbitary. Loki will parse them as-is. Like prometheus, it becomes the primary datasource for log-based data and queries.

Promtail - is a service that runs on the target node. It is what pushes data into Loki (Unlike prometheus, loki does not operate on a pull/scrape model). You can also think of the target as the “source of the logs data”. In this case, our target/source of data is our nginx metrics and logs. Promtail needs read access to the raw log files, and then streams it to Loki. Because of this, I run promtail directly on the nginx container.

assumptions / pre-conditions

Set up the node exporter

There are probably distro packages/procedures for installing the nginx node exporter. Here’s how you can manually do it on linux. I do this from a root shell on the nginx container. The overall process is: download the ‣ binary release, unzip and install the executable somewhere, create a systemd service definition.

# download the binary
cd ~/downloads
wget https://github.com/nginxinc/nginx-prometheus-exporter/releases/download/v0.10.0/nginx-prometheus-exporter_0.10.0_linux_amd64.tar.gz -O ~/downloads/npe.tar.gz
# un-archive
tar -xvf npe.tar.gz
# copy the binary to somewhere sane. Here i've chosen /opt/
cp nginx-prometheus-exporter /opt/

We’ll need to make a systemd service definition file. Here’s mine:

$ cat /etc/systemd/system/nginx-prometheus-exporter.service
[Unit]
Description=Prometheus Node Exporter for Nginx
ConditionFileIsExecutable=/opt/nginx-prometheus-exporter

After=syslog.target network-online.target 

[Service]
StartLimitInterval=5
StartLimitBurst=10
ExecStart=/opt/nginx-prometheus-exporter
SyslogIdentifier=prometheus

WorkingDirectory=/opt/

Restart=always

RestartSec=10

[Install]
WantedBy=multi-user.target

In order for the node exporter to provide useful metrics, we need to enable the stub_status module for nginx. It’s basically a special built-in http endpoint that can be exposed through your nginx conf. This is the relevant snippet, that should go in a sites-enabled or in the root conf:

server {
	server_name nginx;
	listen 8080;  # i'm not sure this port can be changed easily
	location = /stub_status {
		stub_status;
	}
}

On the prometheus node, enable the scraping target

$ cat /etc/prometheus/prometheus.yml
< ... >
- job_name: "nginx_node"
    static_configs:
      - targets: ["nginx:9113"]  # NOTE: this needs to point to your nginx host

Loki + Promtail

As stated in the preface, in order to make the the nginx logs accessible in grafana+loki, we need a promtail instance that can read the raw logs files. On docker-style containers, there’s various incantations to bind-mount the nginx logs directories into a promtail container, but I think it’s just much more straight-forward to install promtail directly in the nginx container. Again, there’s probably a simple and straighforward way to install promtail via your distro’s package manager, but here are the manual steps:

# download the binary
cd ~/downloads
wget https://github.com/grafana/loki/releases/download/v2.4.2/promtail-linux-amd64.zip -O ~/promtail.zip
# unzip and copy to a sane place
unzip promtail.zip
mkdir /opt/promtail
cp /opt/promtail/promtail

Promtail requires a small config file. You can put it anywhere, but I’ll put it in /opt/promtail

$ cat /opt/promtail/promtail.yml 
server:
  http_listen_port: 9080
  grpc_listen_port: 0

positions:
  filename: /tmp/positions.yaml

clients:
                # make sure this host is your LOKI hostname
  - url: http://prometheus:3100/loki/api/v1/push

scrape_configs:
  - job_name: system
    static_configs:
    - targets:
        - localhost
      labels:
        job: varlogs
        __path__: /var/log/*log
  - job_name: nginx
    static_configs:
    - targets:
        - localhost
      labels:
        job: nginx
        __path__: /var/log/nginx/*log

And create a systemd service definition:

$ cat /etc/systemd/system/promtail.service
[Unit]
Description=promtail is the agent responsible for gathering logs and sending them to Loki.
Documentation=https://grafana.com/docs/loki/latest/clients/promtail/
Requires=network-online.target
After=network-online.target

[Service]
Type=simple
ExecStart=/opt/promtail/promtail -positions.file /var/lib/promtail/positions.yml -config.file /opt/promtail/promtail.yml
User=promtail
TimeoutStopSec=30s

NoNewPrivileges=true
MemoryDenyWriteExecute=true
RestrictRealtime=true

ProtectHome=true
ProtectSystem=strict
ReadWritePaths=/var/lib/promtail
PrivateTmp=true

PrivateDevices=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true

[Install]
WantedBy=multi-user.target

Reload systemd and enable and start the new services:

$ systemctl daemon-reload
$ systemctl enable --now promtail
$ systemctl enable --now nginx-prometheus-exporter

You can verify nginx-prometheus-exporter is working by checking its http endpoint: http://nginx:9113/metrics

And promtail: http://nginx:9080/targets

Dashboards in grafana

I’m using dashboard queries and viz based on this dashboard. It requires some slight modifications to the queries to get accurate data. A lot of the queries have extra filters that are specific to the original author.