{ config, lib, pkgs, ... }: with lib; let serviceName = "grafana"; cfg = config.homelab.services.${serviceName}; in { imports = [ (import ../lib/features/monitoring.nix serviceName) (import ../lib/features/logging.nix serviceName) (import ../lib/features/proxy.nix serviceName) ]; options.homelab.services.${serviceName} = { enable = mkEnableOption "Grafana Dashboard"; port = mkOption { type = types.port; default = 3000; }; description = mkOption { type = types.str; default = "Grafana Metrics Dashboard"; }; }; config = mkIf cfg.enable (mkMerge [ # Core Grafana service { services.grafana = { enable = true; settings.server = { http_port = cfg.port; http_addr = "0.0.0.0"; }; }; networking.firewall.allowedTCPPorts = [cfg.port]; homelab.services.${serviceName}.monitoring.enable = mkDefault true; } # Smart defaults for Grafana { # Grafana-specific log setup homelab.services.${serviceName}.logging = mkDefault { files = ["/var/log/grafana/grafana.log"]; parsing = { # Grafana log format: t=2024-01-01T12:00:00Z lvl=info msg="message" regex = "^t=(?P[^ ]+) lvl=(?P\\w+) msg=\"(?P[^\"]*)\""; extractFields = ["level"]; }; extraLabels = { application = "grafana"; component = "dashboard"; }; }; } { homelab.services.${serviceName}.monitoring = mkDefault { metrics.path = "/metrics"; healthCheck = { path = "/api/health"; conditions = ["[STATUS] == 200" "[BODY].database == ok"]; }; extraLabels = { component = "dashboard"; tier = "monitoring"; }; }; } { # Grafana needs auth by default (admin interface) homelab.services.${serviceName}.proxy = mkDefault { subdomain = "grafana"; # enableAuth = true; }; } ]); }