From 9695f7df824a4497b997d6f618b6b85496546b1c Mon Sep 17 00:00:00 2001
From: Martin Fischer <martin@push-f.com>
Date: Sun, 9 Mar 2025 15:43:41 +0100
Subject: feat(tente): add Grafana, Loki, Alloy and Prometheus

---
 nixos/hosts/tente/default.nix    |   5 ++
 nixos/hosts/tente/monitoring.nix | 143 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 148 insertions(+)
 create mode 100644 nixos/hosts/tente/monitoring.nix

(limited to 'nixos')

diff --git a/nixos/hosts/tente/default.nix b/nixos/hosts/tente/default.nix
index b54c378..07b70a4 100644
--- a/nixos/hosts/tente/default.nix
+++ b/nixos/hosts/tente/default.nix
@@ -21,6 +21,7 @@ in
     ./git.nix
     ./headscale.nix
     ./matrix.nix
+    ./monitoring.nix
     "${sources.my-osm-proposals}/service.nix"
   ];
 
@@ -45,6 +46,10 @@ in
       };
     };
 
+  monitoring.grafanaUiPort = 3000;
+  monitoring.alloyUiPort = 3001;
+  monitoring.lokiPort = 3030;
+  monitoring.prometheusExporterPort = 9002;
   headscale.port = 8080;
   matrix.port = 8008;
 
diff --git a/nixos/hosts/tente/monitoring.nix b/nixos/hosts/tente/monitoring.nix
new file mode 100644
index 0000000..bbf4439
--- /dev/null
+++ b/nixos/hosts/tente/monitoring.nix
@@ -0,0 +1,143 @@
+{ config, lib, pkgs, ... }:
+
+let
+  cfg = config.monitoring;
+in
+{
+  options.monitoring = {
+    grafanaUiPort = lib.mkOption {
+      type = lib.types.int;
+    };
+    lokiPort = lib.mkOption {
+      type = lib.types.int;
+    };
+    alloyUiPort = lib.mkOption {
+      type = lib.types.int;
+    };
+    prometheusExporterPort = lib.mkOption {
+      type = lib.types.int;
+    };
+  };
+
+  config = {
+    services.grafana = {
+      enable = true;
+      settings = {
+        server = {
+          http_addr = "0.0.0.0";
+          http_port = cfg.grafanaUiPort;
+        };
+      };
+
+      provision = {
+        enable = true;
+        datasources.settings.datasources = [
+          {
+            name = "Prometheus";
+            type = "prometheus";
+            url = "http://${config.services.prometheus.listenAddress}:${toString config.services.prometheus.port}";
+          }
+          {
+            name = "Loki";
+            type = "loki";
+            access = "proxy";
+            url = "http://127.0.0.1:${toString cfg.lokiPort}";
+          }
+        ];
+      };
+    };
+
+    services.prometheus = {
+      enable = true;
+
+      exporters.node = {
+        enable = true;
+        enabledCollectors = [ "systemd" ];
+        port = cfg.prometheusExporterPort;
+      };
+
+      scrapeConfigs = [
+        {
+          job_name = "node";
+          static_configs = [{
+            targets = [ "localhost:${toString cfg.prometheusExporterPort}" ];
+          }];
+        }
+      ];
+    };
+
+    services.loki = {
+      enable = true;
+      configuration = {
+        server.http_listen_port = cfg.lokiPort;
+        auth_enabled = false;
+
+        ingester = {
+          lifecycler = {
+            address = "127.0.0.1";
+            ring = {
+              kvstore.store = "inmemory";
+              replication_factor = 1;
+            };
+          };
+        };
+
+        schema_config = {
+          configs = [{
+            store = "tsdb";
+            object_store = "filesystem";
+            schema = "v13";
+            index = {
+              prefix = "index_";
+              period = "24h";
+            };
+          }];
+        };
+
+        storage_config = {
+          tsdb_shipper = {
+            active_index_directory = "/var/lib/loki/tsdb-active";
+            cache_location = "/var/lib/loki/tsdb-cache";
+          };
+        };
+
+        compactor = {
+          working_directory = "/var/lib/loki";
+        };
+      };
+    };
+
+    services.alloy = {
+      enable = true;
+      extraFlags = ["--server.http.listen-addr=0.0.0.0:${toString cfg.alloyUiPort}"];
+      # TODO: submit PR to nixpkgs so that the alloy config can be specified as a JSON expression
+      configPath = pkgs.writeText "config.alloy" ''
+        loki.source.journal "journal" {
+          max_age = "12h0m0s"
+          relabel_rules = discovery.relabel.journal.rules
+          forward_to = [loki.write.default.receiver]
+          labels = {
+            host = "tente",
+            job  = "systemd-journal",
+          }
+        }
+
+        discovery.relabel "journal" {
+          targets = []
+
+          rule {
+            source_labels = ["__journal__systemd_unit"]
+            target_label = "unit"
+          }
+        }
+
+        loki.write "default" {
+          endpoint {
+            url = "http://127.0.0.1:${toString cfg.lokiPort}/loki/api/v1/push"
+          }
+          external_labels = {}
+        }
+      '';
+    };
+  };
+}
-- 
cgit v1.2.3