grafana-alloy: don't build the frontend twice
[NixPkgs.git] / nixos / modules / services / monitoring / grafana-agent.nix
blob655ec8ded1e0ff9324a577d6db282a7d65a8aac1
1 { lib, pkgs, config, generators, ... }:
2 with lib;
3 let
4   cfg = config.services.grafana-agent;
5   settingsFormat = pkgs.formats.yaml { };
6   configFile = settingsFormat.generate "grafana-agent.yaml" cfg.settings;
7 in
9   meta = {
10     maintainers = with maintainers; [ flokli zimbatm ];
11   };
13   options.services.grafana-agent = {
14     enable = mkEnableOption "grafana-agent";
16     package = mkPackageOption pkgs "grafana-agent" { };
18     credentials = mkOption {
19       description = ''
20         Credentials to load at service startup. Keys that are UPPER_SNAKE will be loaded as env vars. Values are absolute paths to the credentials.
21       '';
22       type = types.attrsOf types.str;
23       default = { };
25       example = {
26         logs_remote_write_password = "/run/keys/grafana_agent_logs_remote_write_password";
27         LOGS_REMOTE_WRITE_URL = "/run/keys/grafana_agent_logs_remote_write_url";
28         LOGS_REMOTE_WRITE_USERNAME = "/run/keys/grafana_agent_logs_remote_write_username";
29         metrics_remote_write_password = "/run/keys/grafana_agent_metrics_remote_write_password";
30         METRICS_REMOTE_WRITE_URL = "/run/keys/grafana_agent_metrics_remote_write_url";
31         METRICS_REMOTE_WRITE_USERNAME = "/run/keys/grafana_agent_metrics_remote_write_username";
32       };
33     };
35     extraFlags = mkOption {
36       type = with types; listOf str;
37       default = [ ];
38       example = [ "-enable-features=integrations-next" "-disable-reporting" ];
39       description = ''
40         Extra command-line flags passed to {command}`grafana-agent`.
42         See <https://grafana.com/docs/agent/latest/static/configuration/flags/>
43       '';
44     };
46     settings = mkOption {
47       description = ''
48         Configuration for {command}`grafana-agent`.
50         See <https://grafana.com/docs/agent/latest/configuration/>
51       '';
53       type = types.submodule {
54         freeformType = settingsFormat.type;
55       };
57       default = { };
58       defaultText = lib.literalExpression ''
59         {
60           metrics = {
61             wal_directory = "\''${STATE_DIRECTORY}";
62             global.scrape_interval = "5s";
63           };
64           integrations = {
65             agent.enabled = true;
66             agent.scrape_integration = true;
67             node_exporter.enabled = true;
68           };
69         }
70       '';
71       example = {
72         metrics.global.remote_write = [{
73           url = "\${METRICS_REMOTE_WRITE_URL}";
74           basic_auth.username = "\${METRICS_REMOTE_WRITE_USERNAME}";
75           basic_auth.password_file = "\${CREDENTIALS_DIRECTORY}/metrics_remote_write_password";
76         }];
77         logs.configs = [{
78           name = "default";
79           scrape_configs = [
80             {
81               job_name = "journal";
82               journal = {
83                 max_age = "12h";
84                 labels.job = "systemd-journal";
85               };
86               relabel_configs = [
87                 {
88                   source_labels = [ "__journal__systemd_unit" ];
89                   target_label = "systemd_unit";
90                 }
91                 {
92                   source_labels = [ "__journal__hostname" ];
93                   target_label = "nodename";
94                 }
95                 {
96                   source_labels = [ "__journal_syslog_identifier" ];
97                   target_label = "syslog_identifier";
98                 }
99               ];
100             }
101           ];
102           positions.filename = "\${STATE_DIRECTORY}/loki_positions.yaml";
103           clients = [{
104             url = "\${LOGS_REMOTE_WRITE_URL}";
105             basic_auth.username = "\${LOGS_REMOTE_WRITE_USERNAME}";
106             basic_auth.password_file = "\${CREDENTIALS_DIRECTORY}/logs_remote_write_password";
107           }];
108         }];
109       };
110     };
111   };
113   config = mkIf cfg.enable {
114     services.grafana-agent.settings = {
115       # keep this in sync with config.services.grafana-agent.settings.defaultText.
116       metrics = {
117         wal_directory = mkDefault "\${STATE_DIRECTORY}";
118         global.scrape_interval = mkDefault "5s";
119       };
120       integrations = {
121         agent.enabled = mkDefault true;
122         agent.scrape_integration = mkDefault true;
123         node_exporter.enabled = mkDefault true;
124       };
125     };
127     systemd.services.grafana-agent = {
128       wantedBy = [ "multi-user.target" ];
129       script = ''
130         set -euo pipefail
131         shopt -u nullglob
133         # Load all credentials into env if they are in UPPER_SNAKE form.
134         if [[ -n "''${CREDENTIALS_DIRECTORY:-}" ]]; then
135           for file in "$CREDENTIALS_DIRECTORY"/*; do
136             key=$(basename "$file")
137             if [[ $key =~ ^[A-Z0-9_]+$ ]]; then
138               echo "Environ $key"
139               export "$key=$(< "$file")"
140             fi
141           done
142         fi
144         # We can't use Environment=HOSTNAME=%H, as it doesn't include the domain part.
145         export HOSTNAME=$(< /proc/sys/kernel/hostname)
147         exec ${lib.getExe cfg.package} -config.expand-env -config.file ${configFile} ${escapeShellArgs cfg.extraFlags}
148       '';
149       serviceConfig = {
150         Restart = "always";
151         DynamicUser = true;
152         RestartSec = 2;
153         SupplementaryGroups = [
154           # allow to read the systemd journal for loki log forwarding
155           "systemd-journal"
156         ];
157         StateDirectory = "grafana-agent";
158         LoadCredential = lib.mapAttrsToList (key: value: "${key}:${value}") cfg.credentials;
159         Type = "simple";
160       };
161     };
162   };