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