1{ config, lib, utils, pkgs, ... }:
2
3let
4 inherit (lib)
5 attrValues
6 literalExpression
7 mkEnableOption
8 mkIf
9 mkOption
10 types;
11
12 cfg = config.services.filebeat;
13
14 json = pkgs.formats.json {};
15in
16{
17 options = {
18
19 services.filebeat = {
20
21 enable = mkEnableOption (lib.mdDoc "filebeat");
22
23 package = mkOption {
24 type = types.package;
25 default = pkgs.filebeat;
26 defaultText = literalExpression "pkgs.filebeat";
27 example = literalExpression "pkgs.filebeat7";
28 description = lib.mdDoc ''
29 The filebeat package to use.
30 '';
31 };
32
33 inputs = mkOption {
34 description = lib.mdDoc ''
35 Inputs specify how Filebeat locates and processes input data.
36
37 This is like `services.filebeat.settings.filebeat.inputs`,
38 but structured as an attribute set. This has the benefit
39 that multiple NixOS modules can contribute settings to a
40 single filebeat input.
41
42 An input type can be specified multiple times by choosing a
43 different `<name>` for each, but setting
44 [](#opt-services.filebeat.inputs._name_.type)
45 to the same value.
46
47 See <https://www.elastic.co/guide/en/beats/filebeat/current/configuration-filebeat-options.html>.
48 '';
49 default = {};
50 type = types.attrsOf (types.submodule ({ name, ... }: {
51 freeformType = json.type;
52 options = {
53 type = mkOption {
54 type = types.str;
55 default = name;
56 description = lib.mdDoc ''
57 The input type.
58
59 Look for the value after `type:` on
60 the individual input pages linked from
61 <https://www.elastic.co/guide/en/beats/filebeat/current/configuration-filebeat-options.html>.
62 '';
63 };
64 };
65 }));
66 example = literalExpression ''
67 {
68 journald.id = "everything"; # Only for filebeat7
69 log = {
70 enabled = true;
71 paths = [
72 "/var/log/*.log"
73 ];
74 };
75 };
76 '';
77 };
78
79 modules = mkOption {
80 description = lib.mdDoc ''
81 Filebeat modules provide a quick way to get started
82 processing common log formats. They contain default
83 configurations, Elasticsearch ingest pipeline definitions,
84 and Kibana dashboards to help you implement and deploy a log
85 monitoring solution.
86
87 This is like `services.filebeat.settings.filebeat.modules`,
88 but structured as an attribute set. This has the benefit
89 that multiple NixOS modules can contribute settings to a
90 single filebeat module.
91
92 A module can be specified multiple times by choosing a
93 different `<name>` for each, but setting
94 [](#opt-services.filebeat.modules._name_.module)
95 to the same value.
96
97 See <https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-modules.html>.
98 '';
99 default = {};
100 type = types.attrsOf (types.submodule ({ name, ... }: {
101 freeformType = json.type;
102 options = {
103 module = mkOption {
104 type = types.str;
105 default = name;
106 description = lib.mdDoc ''
107 The name of the module.
108
109 Look for the value after `module:` on
110 the individual input pages linked from
111 <https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-modules.html>.
112 '';
113 };
114 };
115 }));
116 example = literalExpression ''
117 {
118 nginx = {
119 access = {
120 enabled = true;
121 var.paths = [ "/path/to/log/nginx/access.log*" ];
122 };
123 error = {
124 enabled = true;
125 var.paths = [ "/path/to/log/nginx/error.log*" ];
126 };
127 };
128 };
129 '';
130 };
131
132 settings = mkOption {
133 type = types.submodule {
134 freeformType = json.type;
135
136 options = {
137
138 output.elasticsearch.hosts = mkOption {
139 type = with types; listOf str;
140 default = [ "127.0.0.1:9200" ];
141 example = [ "myEShost:9200" ];
142 description = lib.mdDoc ''
143 The list of Elasticsearch nodes to connect to.
144
145 The events are distributed to these nodes in round
146 robin order. If one node becomes unreachable, the
147 event is automatically sent to another node. Each
148 Elasticsearch node can be defined as a URL or
149 IP:PORT. For example:
150 `http://192.15.3.2`,
151 `https://es.found.io:9230` or
152 `192.24.3.2:9300`. If no port is
153 specified, `9200` is used.
154 '';
155 };
156
157 filebeat = {
158 inputs = mkOption {
159 type = types.listOf json.type;
160 default = [];
161 internal = true;
162 description = lib.mdDoc ''
163 Inputs specify how Filebeat locates and processes
164 input data. Use [](#opt-services.filebeat.inputs) instead.
165
166 See <https://www.elastic.co/guide/en/beats/filebeat/current/configuration-filebeat-options.html>.
167 '';
168 };
169 modules = mkOption {
170 type = types.listOf json.type;
171 default = [];
172 internal = true;
173 description = lib.mdDoc ''
174 Filebeat modules provide a quick way to get started
175 processing common log formats. They contain default
176 configurations, Elasticsearch ingest pipeline
177 definitions, and Kibana dashboards to help you
178 implement and deploy a log monitoring solution.
179
180 Use [](#opt-services.filebeat.modules) instead.
181
182 See <https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-modules.html>.
183 '';
184 };
185 };
186 };
187 };
188 default = {};
189 example = literalExpression ''
190 {
191 settings = {
192 output.elasticsearch = {
193 hosts = [ "myEShost:9200" ];
194 username = "filebeat_internal";
195 password = { _secret = "/var/keys/elasticsearch_password"; };
196 };
197 logging.level = "info";
198 };
199 };
200 '';
201
202 description = lib.mdDoc ''
203 Configuration for filebeat. See
204 <https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-reference-yml.html>
205 for supported values.
206
207 Options containing secret data should be set to an attribute
208 set containing the attribute `_secret` - a
209 string pointing to a file containing the value the option
210 should be set to. See the example to get a better picture of
211 this: in the resulting
212 {file}`filebeat.yml` file, the
213 `output.elasticsearch.password`
214 key will be set to the contents of the
215 {file}`/var/keys/elasticsearch_password` file.
216 '';
217 };
218 };
219 };
220
221 config = mkIf cfg.enable {
222
223 services.filebeat.settings.filebeat.inputs = attrValues cfg.inputs;
224 services.filebeat.settings.filebeat.modules = attrValues cfg.modules;
225
226 systemd.services.filebeat = {
227 description = "Filebeat log shipper";
228 wantedBy = [ "multi-user.target" ];
229 wants = [ "elasticsearch.service" ];
230 after = [ "elasticsearch.service" ];
231 serviceConfig = {
232 ExecStartPre = pkgs.writeShellScript "filebeat-exec-pre" ''
233 set -euo pipefail
234
235 umask u=rwx,g=,o=
236
237 ${utils.genJqSecretsReplacementSnippet
238 cfg.settings
239 "/var/lib/filebeat/filebeat.yml"
240 }
241 '';
242 ExecStart = ''
243 ${cfg.package}/bin/filebeat -e \
244 -c "/var/lib/filebeat/filebeat.yml" \
245 --path.data "/var/lib/filebeat"
246 '';
247 Restart = "always";
248 StateDirectory = "filebeat";
249 };
250 };
251 };
252}