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