{"id":1195,"date":"2023-09-18T23:08:39","date_gmt":"2023-09-18T23:08:39","guid":{"rendered":"https:\/\/craftcookcode.com\/?p=1195"},"modified":"2023-09-18T23:31:12","modified_gmt":"2023-09-18T23:31:12","slug":"pi-hole-metrics-from-a-postgres-database","status":"publish","type":"post","link":"https:\/\/craftcookcode.com\/?p=1195","title":{"rendered":"Pi-Hole: Metrics from a Postgres database"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-post\" data-elementor-id=\"1195\" class=\"elementor elementor-1195\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-ad5093f elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"ad5093f\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-4818728\" data-id=\"4818728\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-b5e1d3a elementor-widget elementor-widget-text-editor\" data-id=\"b5e1d3a\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>I love <a href=\"https:\/\/pi-hole.net\/\">Pi-Hole<\/a>.<\/p><p>It is one of my favourite services that I have running on my home network.<\/p><p>I definitely take Pi-Hole for granted at home and only really appreciate how effective it is when I travel and connect to other networks.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-6cfbd11 elementor-widget elementor-widget-text-editor\" data-id=\"6cfbd11\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>While the function of Pi-Hole is brilliant &#8211; my Data warehouse Analyst and reporting background craves for more power from the metrics behind Pi-Hole.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-c95e711 elementor-widget elementor-widget-text-editor\" data-id=\"c95e711\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>By default Pi-Hole offers a simple dashboard with a few catchy graphs and metrics.\u00a0 This can be hypnotizing to watch when first installing Pi-Hole; watching shock of how many DNS queries are blocked visiting different\u00a0 websites.<\/p><p>Behind the scenes is a sqlite database located on the server for more power users to query.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-aa7144c elementor-widget elementor-widget-heading\" data-id=\"aa7144c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h3 class=\"elementor-heading-title elementor-size-default\">We need more power!<\/h3>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-bd48935 elementor-widget elementor-widget-text-editor\" data-id=\"bd48935\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>For me &#8211; I have a couple of problems with the Pi-Hole dashboard and crave for more functionality and power from what is on offer.<\/p><p>Some issues I have:<\/p><ul><li>On my home network &#8211; I have two Pi-Hole servers working in a redundancy.\u00a0 The main Pi-Hole server is sitting on a hypervisor while the backup one is on a Raspberry Pi.\u00a0 The main rational of this is that if we have a power outage that knocks the hypervisor offline while I am not at home; the backup Pi-Hole server will take over and save an angry phone call from the wife on why she can&#8217;t access the internet.<br \/><br \/>One of my wishes is to see the combined Pi-Hole metrics across both servers in one dashboard.<br \/><br \/><\/li><li>A couple of items on the network creates a large amount of noise that skews the metrics.\u00a0 For instance the security cameras use to query a NTP server every second until I routed them through a NTP server at home.\u00a0 My work computer when it drops off the VPN will flood particular addresses with traffic.\u00a0 <br \/><br \/>I would like to exclude these addresses from the metrics; but not exclude them from the P-Hole functionality.<br \/><br \/><\/li><li>Access to better analytics from the Pi-Hole data.\u00a0<ul><li>How about a heat map of blocked queries on devices?\u00a0<\/li><li>Or weekly trends with a moving average?\u00a0<\/li><li>Or ability to drill into a time where there is a high amount of blocked traffic to determine the\u00a0 device and application is behind it? (Answer: My kid playing mobile app games)<\/li><\/ul><\/li><\/ul>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-81d64d2 elementor-widget elementor-widget-heading\" data-id=\"81d64d2\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h3 class=\"elementor-heading-title elementor-size-default\">Napkin Solution<\/h3>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-ecad49c elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"ecad49c\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-0a55bb4\" data-id=\"0a55bb4\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-4482c33 elementor-widget elementor-widget-text-editor\" data-id=\"4482c33\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>This is what I am working on at the moment to extract and load the data from my two Pi-Hole servers into a Postgres database to query from.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-2dab5c8 elementor-widget elementor-widget-image\" data-id=\"2dab5c8\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"image.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<img fetchpriority=\"high\" decoding=\"async\" width=\"740\" height=\"290\" src=\"https:\/\/craftcookcode.com\/wp-content\/uploads\/2023\/09\/code_pihole_reporting-1024x401.png\" class=\"attachment-large size-large wp-image-1200\" alt=\"\" srcset=\"https:\/\/craftcookcode.com\/wp-content\/uploads\/2023\/09\/code_pihole_reporting-1024x401.png 1024w, https:\/\/craftcookcode.com\/wp-content\/uploads\/2023\/09\/code_pihole_reporting-300x117.png 300w, https:\/\/craftcookcode.com\/wp-content\/uploads\/2023\/09\/code_pihole_reporting-768x301.png 768w, https:\/\/craftcookcode.com\/wp-content\/uploads\/2023\/09\/code_pihole_reporting-1536x601.png 1536w, https:\/\/craftcookcode.com\/wp-content\/uploads\/2023\/09\/code_pihole_reporting-2048x802.png 2048w\" sizes=\"(max-width: 740px) 100vw, 740px\" \/>\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-187738c elementor-widget elementor-widget-text-editor\" data-id=\"187738c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<ol><li>A NFS share is set up to share out the pihole-FLT.db to a linux server on both Pi-Hole servers<\/li><li>A cron job runs every <em>x<\/em> minutes to run a python script.\u00a0 The python scrip will query the pihole-FTL.db to get the records from the last timestamp it ran to the current timestamp in the Pi-Hole database and land the data in to a &#8220;landing&#8221; schema on the postgres database<\/li><li>A stored procedure will run to transfer and normalise the data into an ods schema<\/li><li>A reporting tool will then query off the ods schema.\u00a0 In this case I am using Apache Superset; just because it was freely available and the web nature means I can share dashboards to multiple devices without installing client software.<\/li><\/ol>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-4475558 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"4475558\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-09e8b6a\" data-id=\"09e8b6a\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-1751c32 elementor-widget elementor-widget-heading\" data-id=\"1751c32\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h4 class=\"elementor-heading-title elementor-size-default\">Performance of querying sqlite through a NFS share <\/h4>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-d4d6d7c elementor-widget elementor-widget-text-editor\" data-id=\"d4d6d7c\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>Initially I was worried about querying the pihole-FTL.db over the NFS share; thinking it will be too slow to be practical.<\/p><p>I was thinking of a few clunky solutions:<\/p><ol><li>Copy the entire DB over to the postgres host and load it from there<\/li><li>Write a script that runs on the Pi-Hole server to extract the incremental data from the pihole-FLT.db into files and load the files<\/li><\/ol><p>Thankfully from the volume of traffic we produce; it is not a concern.<\/p><p>The initial load of copying all the data out of the Pi-Hole database does take a long time if there is a large amount of history to transfer across.<\/p><p>But once the initial load is done; small incremental bites of data only take a few seconds<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-81679a4 elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"81679a4\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-901bd0c\" data-id=\"901bd0c\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-bdd2460 elementor-widget elementor-widget-heading\" data-id=\"bdd2460\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"heading.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<h3 class=\"elementor-heading-title elementor-size-default\">Current state<\/h3>\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-98060ac elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"98060ac\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-4999e50\" data-id=\"4999e50\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-09442a7 elementor-widget elementor-widget-text-editor\" data-id=\"09442a7\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"text-editor.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t\t\t\t\t<p>I have a pilot running on my home network as a proof of concept.<\/p><p>Fundamentally it works fine and I can gleam some interesting metrics from my Pi-Hole servers.<\/p><p>At the moment the security is <del>not great<\/del> atrocious as I am just using a super username and password throughout the pipeline.<\/p><p>Once I have cleaned up the postgres sql, python code I can share the complete solution.<\/p>\t\t\t\t\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>I love Pi-Hole. It is one of my favourite services that I have running on my home network. I definitely take Pi-Hole for granted at home&#46;&#46;&#46;<\/p>\n","protected":false},"author":1,"featured_media":1201,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"footnotes":""},"categories":[54],"tags":[55,56,57],"class_list":["post-1195","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-pihole","tag-pihole","tag-postgres","tag-superset"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/craftcookcode.com\/index.php?rest_route=\/wp\/v2\/posts\/1195","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/craftcookcode.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/craftcookcode.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/craftcookcode.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/craftcookcode.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1195"}],"version-history":[{"count":7,"href":"https:\/\/craftcookcode.com\/index.php?rest_route=\/wp\/v2\/posts\/1195\/revisions"}],"predecessor-version":[{"id":1204,"href":"https:\/\/craftcookcode.com\/index.php?rest_route=\/wp\/v2\/posts\/1195\/revisions\/1204"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/craftcookcode.com\/index.php?rest_route=\/wp\/v2\/media\/1201"}],"wp:attachment":[{"href":"https:\/\/craftcookcode.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1195"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/craftcookcode.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1195"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/craftcookcode.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1195"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}