Graphing Pi-Hole stats with Graphite and Grafana

Everyone loves the Pi-Hole. It does a great job blockig ad’s across your entire network. The admin page is also really useful to see whats been going on. Unfortunately the admin interface only gives details of the last 24 hours. I love graphs and graphing things. So i wanted more data.

I already had Graphite and Grafana setup for my previous projects. I just needed a way to get the data into them.

Luckily, the Pi-hole guys provide a nice little API wich provides these details. The following is a small python script is knocked up which pulls and parses that API then forwards the data into my Graphite server.

#! /usr/bin/python

import requests
import socket
import time
import platform

HOSTNAME = "pi-hole"
CARBON_SERVER = "192.168.0.175"
CARBON_PORT = 2003
DELAY = 10 # seconds

def send_msg(message):
#    print ('sending message:\n%s' % message)
    sock = socket.socket()
    sock.connect((CARBON_SERVER, CARBON_PORT))
    sock.sendall(message)
    sock.close()

if __name__ == '__main__':
        while True:
          api = requests.get('http://192.168.0.131/admin/api.php')
          API_out = api.json()
# I could just iterate through the response. But by explicitly defining each one i wont have an issue should the order change.
          domains_blocked = (API_out['domains_being_blocked']).replace(',', '')
          dns_queries_today = (API_out['dns_queries_today']).replace(',', '')
          ads_percentage_today = (API_out['ads_percentage_today'])
          ads_blocked_today = (API_out['ads_blocked_today']).replace(',', '')

          timestamp = int(time.time())

          lines = [
                'pihole.%s.domains_blocked %s %d' % (HOSTNAME, domains_blocked, timestamp),
                'pihole.%s.dns_queries_today %s %d' % (HOSTNAME, dns_queries_today, timestamp),
                'pihole.%s.ads_percentage_today %s %d' % (HOSTNAME, ads_percentage_today, timestamp),
                'pihole.%s.ads_blocked_today %s %d' % (HOSTNAME, ads_blocked_today, timestamp)
          ]
          message = '\n'.join(lines) + '\n'
          send_msg(message)
          time.sleep(DELAY)

My python is probably not the greatest. But it does work. Here are my current graphs.

6 Hour

24 Hour

7 days

Finally, to get the “Currently blocked” i use the “Derivative” modifier in Grafana, like this: